mortar 0.12.2 → 0.12.3
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/lib/mortar/command/base.rb +2 -2
- data/lib/mortar/command/config.rb +149 -0
- data/lib/mortar/command/projects.rb +1 -1
- data/lib/mortar/git.rb +50 -18
- data/lib/mortar/version.rb +1 -1
- data/spec/mortar/command/config_spec.rb +237 -0
- data/spec/mortar/git_spec.rb +29 -7
- data/spec/spec_helper.rb +7 -2
- metadata +49 -17
- checksums.yaml +0 -7
data/lib/mortar/command/base.rb
CHANGED
@@ -172,7 +172,7 @@ class Mortar::Command::Base
|
|
172
172
|
File.open(".mortar-project-remote", "w") do |f|
|
173
173
|
f.puts api_registration_result["git_url"]
|
174
174
|
end
|
175
|
-
git.sync_embedded_project(project, "master")
|
175
|
+
git.sync_embedded_project(project, "master", git_organization)
|
176
176
|
end
|
177
177
|
|
178
178
|
protected
|
@@ -446,7 +446,7 @@ protected
|
|
446
446
|
def sync_code_with_cloud
|
447
447
|
# returns git_ref
|
448
448
|
if project.embedded_project?
|
449
|
-
return git.sync_embedded_project(project, embedded_project_user_branch)
|
449
|
+
return git.sync_embedded_project(project, embedded_project_user_branch, git_organization)
|
450
450
|
else
|
451
451
|
validate_git_based_project!
|
452
452
|
return git.create_and_push_snapshot_branch(project)
|
@@ -0,0 +1,149 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2013 Mortar Data Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# Portions of this code from heroku (https://github.com/heroku/heroku/) Copyright Heroku 2008 - 2013,
|
17
|
+
# used under an MIT license (https://github.com/heroku/heroku/blob/master/LICENSE).
|
18
|
+
#
|
19
|
+
|
20
|
+
require "mortar/command/base"
|
21
|
+
|
22
|
+
# manage project config variables
|
23
|
+
#
|
24
|
+
class Mortar::Command::Config < Mortar::Command::Base
|
25
|
+
|
26
|
+
# config
|
27
|
+
#
|
28
|
+
# Display the config vars for a project.
|
29
|
+
#
|
30
|
+
# -s, --shell # output config vars in shell format
|
31
|
+
#
|
32
|
+
#
|
33
|
+
# $ mortar config
|
34
|
+
# A: one
|
35
|
+
# B: two
|
36
|
+
#
|
37
|
+
# $ mortar config --shell
|
38
|
+
# A=one
|
39
|
+
# B=two
|
40
|
+
#
|
41
|
+
def index
|
42
|
+
validate_arguments!
|
43
|
+
project_name = options[:project] || project.name
|
44
|
+
vars = api.get_config_vars(project_name).body['config']
|
45
|
+
if vars.empty?
|
46
|
+
display("#{project_name} has no config vars.")
|
47
|
+
else
|
48
|
+
vars.each {|key, value| vars[key] = value.to_s}
|
49
|
+
if options[:shell]
|
50
|
+
vars.keys.sort.each do |key|
|
51
|
+
display(%{#{key}=#{vars[key]}})
|
52
|
+
end
|
53
|
+
else
|
54
|
+
styled_header("#{project_name} Config Vars")
|
55
|
+
styled_hash(vars)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# config:get KEY
|
61
|
+
#
|
62
|
+
# display a config var for a project
|
63
|
+
#
|
64
|
+
#Examples:
|
65
|
+
#
|
66
|
+
# $ mortar config:get MY_CONFIG_VAR
|
67
|
+
# one
|
68
|
+
#
|
69
|
+
def get
|
70
|
+
unless key = shift_argument
|
71
|
+
error("Usage: mortar config:get KEY\nMust specify KEY.")
|
72
|
+
end
|
73
|
+
validate_arguments!
|
74
|
+
project_name = options[:project] || project.name
|
75
|
+
|
76
|
+
vars = api.get_config_vars(project_name).body['config']
|
77
|
+
key_name, value = vars.detect {|k,v| k == key}
|
78
|
+
unless key_name
|
79
|
+
error("Config var #{key} is not defined for project #{project_name}.")
|
80
|
+
end
|
81
|
+
|
82
|
+
display(value.to_s)
|
83
|
+
end
|
84
|
+
|
85
|
+
# config:set KEY1=VALUE1 [KEY2=VALUE2 ...]
|
86
|
+
#
|
87
|
+
# Set one or more config vars
|
88
|
+
#
|
89
|
+
#Example:
|
90
|
+
#
|
91
|
+
# $ mortar config:set A=one
|
92
|
+
# Setting config vars... done.
|
93
|
+
# A: one
|
94
|
+
#
|
95
|
+
# $ mortar config:set A=one B=two
|
96
|
+
# Setting config vars... done.
|
97
|
+
# A: one
|
98
|
+
# B: two
|
99
|
+
#
|
100
|
+
def set
|
101
|
+
unless args.size > 0 and args.all? { |a| a.include?('=') }
|
102
|
+
error("Usage: mortar config:set KEY1=VALUE1 [KEY2=VALUE2 ...]\nMust specify KEY and VALUE to set.")
|
103
|
+
end
|
104
|
+
|
105
|
+
vars = args.inject({}) do |vars, arg|
|
106
|
+
key, value = arg.split('=', 2)
|
107
|
+
vars[key] = value
|
108
|
+
vars
|
109
|
+
end
|
110
|
+
|
111
|
+
project_name = options[:project] || project.name
|
112
|
+
|
113
|
+
action("Setting config vars for project #{project_name}") do
|
114
|
+
api.put_config_vars(project_name, vars)
|
115
|
+
end
|
116
|
+
|
117
|
+
vars.each {|key, value| vars[key] = value.to_s}
|
118
|
+
styled_hash(vars)
|
119
|
+
end
|
120
|
+
|
121
|
+
alias_command "config:add", "config:set"
|
122
|
+
alias_command "config:put", "config:set"
|
123
|
+
|
124
|
+
# config:unset KEY1 [KEY2 ...]
|
125
|
+
#
|
126
|
+
# unset one or more config vars
|
127
|
+
#
|
128
|
+
# $ mortar config:unset A
|
129
|
+
# Unsetting A... done
|
130
|
+
#
|
131
|
+
# $ mortar config:unset A B
|
132
|
+
# Unsetting A... done
|
133
|
+
# Unsetting B... done
|
134
|
+
#
|
135
|
+
def unset
|
136
|
+
if args.empty?
|
137
|
+
error("Usage: mortar config:unset KEY1 [KEY2 ...]\nMust specify KEY to unset.")
|
138
|
+
end
|
139
|
+
project_name = options[:project] || project.name
|
140
|
+
args.each do |key|
|
141
|
+
action("Unsetting #{key} for project #{project_name}") do
|
142
|
+
api.delete_config_var(project_name, key)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
alias_command "config:remove", "config:unset"
|
148
|
+
|
149
|
+
end
|
@@ -188,7 +188,7 @@ class Mortar::Command::Projects < Mortar::Command::Base
|
|
188
188
|
File.open(".mortar-project-remote", "w") do |f|
|
189
189
|
f.puts project["git_url"]
|
190
190
|
end
|
191
|
-
git.sync_embedded_project(project, embedded_project_user_branch)
|
191
|
+
git.sync_embedded_project(project, embedded_project_user_branch, git_organization)
|
192
192
|
else
|
193
193
|
git.remote_add("mortar", project["git_url"])
|
194
194
|
end
|
data/lib/mortar/git.rb
CHANGED
@@ -249,7 +249,7 @@ module Mortar
|
|
249
249
|
"/tmp/mortar-git-mirrors"
|
250
250
|
end
|
251
251
|
|
252
|
-
def sync_embedded_project(project, branch)
|
252
|
+
def sync_embedded_project(project, branch, git_organization)
|
253
253
|
# the project is not a git repo, so we manage a mirror directory that is a git repo
|
254
254
|
# branch is which branch to sync to. this will be master if the cloud repo
|
255
255
|
# is being initialized, or a branch based on the user's name in any other circumstance
|
@@ -257,7 +257,7 @@ module Mortar
|
|
257
257
|
project_dir = project.root_path
|
258
258
|
mirror_dir = "#{mortar_mirrors_dir}/#{project.name}"
|
259
259
|
|
260
|
-
ensure_embedded_project_mirror_exists(mirror_dir)
|
260
|
+
ensure_embedded_project_mirror_exists(mirror_dir, git_organization)
|
261
261
|
sync_embedded_project_with_mirror(mirror_dir, project_dir, branch)
|
262
262
|
git_ref = sync_embedded_project_mirror_with_cloud(mirror_dir, branch)
|
263
263
|
|
@@ -265,7 +265,7 @@ module Mortar
|
|
265
265
|
return git_ref
|
266
266
|
end
|
267
267
|
|
268
|
-
def ensure_embedded_project_mirror_exists(mirror_dir)
|
268
|
+
def ensure_embedded_project_mirror_exists(mirror_dir, git_organization)
|
269
269
|
# create and initialize mirror git repo if it doesn't already exist
|
270
270
|
unless File.directory? mirror_dir
|
271
271
|
unless File.directory? mortar_mirrors_dir
|
@@ -276,33 +276,57 @@ module Mortar
|
|
276
276
|
remote_path = File.open(".mortar-project-remote").read.strip
|
277
277
|
clone(remote_path, mirror_dir)
|
278
278
|
|
279
|
-
# make an initial commit to the specified branch
|
280
279
|
Dir.chdir(mirror_dir)
|
280
|
+
|
281
|
+
# ensure that the mortar remote is defined
|
282
|
+
unless remotes(git_organization).include? "mortar"
|
283
|
+
git("remote add mortar #{remote_path}")
|
284
|
+
end
|
285
|
+
|
286
|
+
# make an initial commit to the specified branch
|
281
287
|
unless File.exists? ".gitkeep" # flag that signals that the repo has been initialized
|
282
288
|
# initialization is not necessary if this is not the first user to use it
|
283
289
|
File.open(".gitkeep", "w").close()
|
284
290
|
git("add .")
|
285
291
|
git("commit -m \"Setting up embedded Mortar project\"")
|
286
|
-
git("remote add mortar #{remote_path}")
|
287
292
|
push_with_retry("mortar", "master", "Setting up embedded Mortar project")
|
288
293
|
end
|
289
294
|
end
|
290
295
|
end
|
291
296
|
|
292
|
-
def sync_embedded_project_with_mirror(mirror_dir, project_dir,
|
297
|
+
def sync_embedded_project_with_mirror(mirror_dir, project_dir, local_branch)
|
293
298
|
# pull from remote branch and overwrite everything, if it exists.
|
294
299
|
# if it doesn't exist, create it.
|
295
300
|
Dir.chdir(mirror_dir)
|
296
|
-
|
301
|
+
|
302
|
+
# stash any local changes
|
303
|
+
# so we can change branches w/ impunity
|
304
|
+
stash_working_dir("cleaning out mirror working directory")
|
305
|
+
|
306
|
+
# fetch remotes
|
297
307
|
git("fetch --all")
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
308
|
+
|
309
|
+
remote_branch = "mortar/#{local_branch}"
|
310
|
+
if branches.include?(local_branch)
|
311
|
+
# if the local branch already exists, use that
|
312
|
+
git("checkout #{local_branch}")
|
313
|
+
|
314
|
+
# if a remote branch exists, hard reset the local branch to that
|
315
|
+
# to avoid push conflicts
|
316
|
+
if all_branches.include?("remotes/#{remote_branch}")
|
317
|
+
git("reset --hard #{remote_branch}")
|
318
|
+
end
|
319
|
+
else
|
320
|
+
# start a new local branch off of master
|
321
|
+
git("checkout master")
|
322
|
+
|
323
|
+
# if a remote branch exists, checkout the local to track the remote
|
324
|
+
if all_branches.include?("remotes/#{remote_branch}")
|
325
|
+
# track the remote branch
|
326
|
+
git("checkout -b #{local_branch} #{remote_branch}")
|
304
327
|
else
|
305
|
-
|
328
|
+
# start a new branch, nothing to track
|
329
|
+
git("checkout -b #{local_branch}")
|
306
330
|
end
|
307
331
|
end
|
308
332
|
|
@@ -329,8 +353,9 @@ module Mortar
|
|
329
353
|
snapshot_branch = "mortar-snapshot-#{Mortar::UUID.create_random.to_s}"
|
330
354
|
git("checkout -b #{snapshot_branch}")
|
331
355
|
|
332
|
-
# push
|
333
|
-
|
356
|
+
# push base branch and snapshot branch
|
357
|
+
push_with_retry("mortar", branch, "Sending code base branch to Mortar")
|
358
|
+
git_ref = push_with_retry("mortar", snapshot_branch, "Sending code snapshot to Mortar")
|
334
359
|
|
335
360
|
git("checkout #{branch}")
|
336
361
|
return git_ref
|
@@ -352,6 +377,13 @@ module Mortar
|
|
352
377
|
git("branch")
|
353
378
|
end
|
354
379
|
|
380
|
+
#
|
381
|
+
# Includes remote tracking branches.
|
382
|
+
#
|
383
|
+
def all_branches
|
384
|
+
git("branch --all")
|
385
|
+
end
|
386
|
+
|
355
387
|
def current_branch
|
356
388
|
branches.split("\n").each do |branch_listing|
|
357
389
|
|
@@ -415,13 +447,13 @@ module Mortar
|
|
415
447
|
#
|
416
448
|
# remotes
|
417
449
|
#
|
418
|
-
|
419
450
|
def remotes(git_organization)
|
420
451
|
# returns {git_remote_name => project_name}
|
421
452
|
remotes = {}
|
422
453
|
git("remote -v").split("\n").each do |remote|
|
423
454
|
name, url, method = remote.split(/\s/)
|
424
|
-
if url =~ /^git@([\w\d\.]+):#{git_organization}\/[a-zA-Z0-9]+_([\w\d-]+)\.git$$/
|
455
|
+
if url =~ /^git@([\w\d\.]+):#{git_organization}\/[a-zA-Z0-9]+_([\w\d-]+)\.git$$/ ||
|
456
|
+
url =~ /^git@([\w\d\.]+):#{git_organization}\/([\w\d-]+)\.git$$/
|
425
457
|
remotes[name] = $2
|
426
458
|
end
|
427
459
|
end
|
data/lib/mortar/version.rb
CHANGED
@@ -0,0 +1,237 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2013 Mortar Data Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
# Portions of this code from heroku (https://github.com/heroku/heroku/) Copyright Heroku 2008 - 2013,
|
17
|
+
# used under an MIT license (https://github.com/heroku/heroku/blob/master/LICENSE).
|
18
|
+
#
|
19
|
+
|
20
|
+
require "spec_helper"
|
21
|
+
require "mortar/command/config"
|
22
|
+
|
23
|
+
module Mortar::Command
|
24
|
+
describe Config do
|
25
|
+
before(:each) do
|
26
|
+
stub_core
|
27
|
+
@git = Mortar::Git::Git.new
|
28
|
+
end
|
29
|
+
|
30
|
+
context("index") do
|
31
|
+
it "shows an empty collection of configs" do
|
32
|
+
with_git_initialized_project do |p|
|
33
|
+
# stub api request
|
34
|
+
configs = {}
|
35
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
36
|
+
|
37
|
+
stderr, stdout = execute("config", p, @git)
|
38
|
+
stdout.should == <<-STDOUT
|
39
|
+
myproject has no config vars.
|
40
|
+
STDOUT
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "shows a populated collection of configs" do
|
45
|
+
with_git_initialized_project do |p|
|
46
|
+
# stub api request
|
47
|
+
configs = {"foo" => "ABCDEFGHIJKLMNOP", "BAR" => "sheepdog"}
|
48
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
49
|
+
|
50
|
+
stderr, stdout = execute("config", p, @git)
|
51
|
+
stdout.should == <<-STDOUT
|
52
|
+
=== myproject Config Vars
|
53
|
+
BAR: sheepdog
|
54
|
+
foo: ABCDEFGHIJKLMNOP
|
55
|
+
STDOUT
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not trim long values" do
|
60
|
+
with_git_initialized_project do |p|
|
61
|
+
# stub api request
|
62
|
+
configs = {'LONG' => 'A' * 60 }
|
63
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
64
|
+
|
65
|
+
stderr, stdout = execute("config", p, @git)
|
66
|
+
stdout.should == <<-STDOUT
|
67
|
+
=== myproject Config Vars
|
68
|
+
LONG: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
69
|
+
STDOUT
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "handles when value is nil" do
|
74
|
+
with_git_initialized_project do |p|
|
75
|
+
# stub api request
|
76
|
+
configs = { 'FOO_BAR' => 'one', 'BAZ_QUX' => nil }
|
77
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
78
|
+
|
79
|
+
stderr, stdout = execute("config", p, @git)
|
80
|
+
stdout.should == <<-STDOUT
|
81
|
+
=== myproject Config Vars
|
82
|
+
BAZ_QUX:
|
83
|
+
FOO_BAR: one
|
84
|
+
STDOUT
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "handles when value is a boolean" do
|
89
|
+
with_git_initialized_project do |p|
|
90
|
+
# stub api request
|
91
|
+
configs = {'FOO_BAR' => 'one', 'BAZ_QUX' => true}
|
92
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
93
|
+
|
94
|
+
stderr, stdout = execute("config", p, @git)
|
95
|
+
stdout.should == <<-STDOUT
|
96
|
+
=== myproject Config Vars
|
97
|
+
BAZ_QUX: true
|
98
|
+
FOO_BAR: one
|
99
|
+
STDOUT
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it "shows configs in a shell compatible format" do
|
104
|
+
with_git_initialized_project do |p|
|
105
|
+
# stub api request
|
106
|
+
configs = {'A' => 'one', 'B' => 'two three'}
|
107
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
108
|
+
|
109
|
+
stderr, stdout = execute("config --shell", p, @git)
|
110
|
+
stdout.should == <<-STDOUT
|
111
|
+
A=one
|
112
|
+
B=two three
|
113
|
+
STDOUT
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context("get") do
|
119
|
+
it "shows a single config for get" do
|
120
|
+
with_git_initialized_project do |p|
|
121
|
+
# stub api request
|
122
|
+
configs = {"foo" => "ABCDEFGHIJKLMNOP", "BAR" => "sheepdog"}
|
123
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
124
|
+
|
125
|
+
stderr, stdout = execute("config:get BAR", p, @git)
|
126
|
+
stdout.should == <<-STDOUT
|
127
|
+
sheepdog
|
128
|
+
STDOUT
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it "errors when a config is missing" do
|
133
|
+
with_git_initialized_project do |p|
|
134
|
+
# stub api request
|
135
|
+
configs = {"foo" => "ABCDEFGHIJKLMNOP", "BAR" => "sheepdog"}
|
136
|
+
mock(Mortar::Auth.api).get_config_vars("myproject").returns(Excon::Response.new(:body => {"config" => configs}))
|
137
|
+
|
138
|
+
stderr, stdout = execute("config:get NOPE", p, @git)
|
139
|
+
stderr.should == <<-STDERR
|
140
|
+
! Config var NOPE is not defined for project myproject.
|
141
|
+
STDERR
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
context("set") do
|
147
|
+
it "sets config vars" do
|
148
|
+
with_git_initialized_project do |p|
|
149
|
+
# stub api request
|
150
|
+
configs = {'A' => '1', 'B' => '2'}
|
151
|
+
mock(Mortar::Auth.api).put_config_vars("myproject", configs).returns(Excon::Response.new(:body => {}))
|
152
|
+
|
153
|
+
stderr, stdout = execute("config:set A=1 B=2", p, @git)
|
154
|
+
stderr.should == ""
|
155
|
+
stdout.should == <<-STDOUT
|
156
|
+
Setting config vars for project myproject... done
|
157
|
+
A: 1
|
158
|
+
B: 2
|
159
|
+
STDOUT
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
it "allows config vars with = in the value" do
|
164
|
+
with_git_initialized_project do |p|
|
165
|
+
# stub api request
|
166
|
+
configs = {'A' => 'b=c'}
|
167
|
+
mock(Mortar::Auth.api).put_config_vars("myproject", configs).returns(Excon::Response.new(:body => {}))
|
168
|
+
|
169
|
+
stderr, stdout = execute("config:set A=b=c", p, @git)
|
170
|
+
stderr.should == ""
|
171
|
+
stdout.should == <<-STDOUT
|
172
|
+
Setting config vars for project myproject... done
|
173
|
+
A: b=c
|
174
|
+
STDOUT
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
it "sets config vars without changing case" do
|
180
|
+
with_git_initialized_project do |p|
|
181
|
+
# stub api request
|
182
|
+
configs = {'a' => 'b'}
|
183
|
+
mock(Mortar::Auth.api).put_config_vars("myproject", configs).returns(Excon::Response.new(:body => {}))
|
184
|
+
|
185
|
+
stderr, stdout = execute("config:set a=b", p, @git)
|
186
|
+
stderr.should == ""
|
187
|
+
stdout.should == <<-STDOUT
|
188
|
+
Setting config vars for project myproject... done
|
189
|
+
a: b
|
190
|
+
STDOUT
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
|
196
|
+
context("unset") do
|
197
|
+
it "errors when no keys are provided" do
|
198
|
+
with_git_initialized_project do |p|
|
199
|
+
stderr, stdout = execute("config:unset", p, @git)
|
200
|
+
stderr.should == <<-STDERR
|
201
|
+
! Usage: mortar config:unset KEY1 [KEY2 ...]
|
202
|
+
! Must specify KEY to unset.
|
203
|
+
STDERR
|
204
|
+
stdout.should == ""
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it "unsets one key" do
|
209
|
+
with_git_initialized_project do |p|
|
210
|
+
# stub api requests
|
211
|
+
mock(Mortar::Auth.api).delete_config_var("myproject", "A").returns(Excon::Response.new(:body => {}))
|
212
|
+
|
213
|
+
stderr, stdout = execute("config:unset A", p, @git)
|
214
|
+
stderr.should == ""
|
215
|
+
stdout.should == <<-STDOUT
|
216
|
+
Unsetting A for project myproject... done
|
217
|
+
STDOUT
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
it "unsets two keys" do
|
222
|
+
with_git_initialized_project do |p|
|
223
|
+
# stub api requests
|
224
|
+
mock(Mortar::Auth.api).delete_config_var("myproject", "A").returns(Excon::Response.new(:body => {}))
|
225
|
+
mock(Mortar::Auth.api).delete_config_var("myproject", "B").returns(Excon::Response.new(:body => {}))
|
226
|
+
|
227
|
+
stderr, stdout = execute("config:unset A B", p, @git)
|
228
|
+
stderr.should == ""
|
229
|
+
stdout.should == <<-STDOUT
|
230
|
+
Unsetting A for project myproject... done
|
231
|
+
Unsetting B for project myproject... done
|
232
|
+
STDOUT
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
data/spec/mortar/git_spec.rb
CHANGED
@@ -226,6 +226,13 @@ STASH
|
|
226
226
|
remotes["mortar"].should == p.name
|
227
227
|
end
|
228
228
|
end
|
229
|
+
|
230
|
+
it "finds new style project name remote" do
|
231
|
+
with_git_initialized_project_with_remote_prefix("") do |p|
|
232
|
+
remotes = @git.remotes("mortarcode-dev")
|
233
|
+
remotes["mortar"].should == p.name
|
234
|
+
end
|
235
|
+
end
|
229
236
|
|
230
237
|
end
|
231
238
|
|
@@ -309,14 +316,19 @@ STASH
|
|
309
316
|
it "creates a mirror directory for the project when one does not already exist" do
|
310
317
|
with_embedded_project do |p|
|
311
318
|
mirror_dir = File.join(Dir.tmpdir, "mortar", "test-git-mirror")
|
319
|
+
FileUtils.rm_rf(mirror_dir)
|
312
320
|
mock(@git).mortar_mirrors_dir.any_times { mirror_dir }
|
313
321
|
|
314
322
|
mock(@git).git.with_any_args.any_times { true }
|
323
|
+
mock(@git).remotes.with_any_args.any_times { {"origin"=> "git@github.com:mortarcode-dev/4dbbd83cae8d5bf8a4000000_#{p.name}.git"} }
|
315
324
|
mock(@git).clone.with_any_args.times(1) { FileUtils.mkdir("#{mirror_dir}/#{p.name}") }
|
316
|
-
mock(@git).push_with_retry.with_any_args.times(
|
325
|
+
mock(@git).push_with_retry.with_any_args.times(3) { true }
|
317
326
|
mock(@git).is_clean_working_directory? { false }
|
318
|
-
|
319
|
-
@git.
|
327
|
+
mock(@git).did_stash_changes?.with_any_args.any_times { false }
|
328
|
+
mock(@git).branches.any_times { "master" }
|
329
|
+
mock(@git).all_branches.any_times { "master\nremotes/mortar/master" }
|
330
|
+
|
331
|
+
@git.sync_embedded_project(p, "master", "mortarcode-dev")
|
320
332
|
|
321
333
|
File.directory?(mirror_dir).should be_true
|
322
334
|
FileUtils.rm_rf(mirror_dir)
|
@@ -326,6 +338,7 @@ STASH
|
|
326
338
|
it "syncs files to the project mirror" do
|
327
339
|
with_embedded_project do |p|
|
328
340
|
mirror_dir = File.join(Dir.tmpdir, "mortar", "test-git-mirror")
|
341
|
+
FileUtils.rm_rf(mirror_dir)
|
329
342
|
mock(@git).mortar_mirrors_dir.any_times { mirror_dir }
|
330
343
|
|
331
344
|
project_mirror_dir = File.join(mirror_dir, p.name)
|
@@ -333,11 +346,15 @@ STASH
|
|
333
346
|
FileUtils.touch("#{p.root_path}/pigscripts/calydonian_boar.pig")
|
334
347
|
|
335
348
|
mock(@git).git.with_any_args.any_times { true }
|
349
|
+
mock(@git).remotes.with_any_args.any_times { {"origin"=> "git@github.com:mortarcode-dev/4dbbd83cae8d5bf8a4000000_#{p.name}.git"} }
|
336
350
|
mock(@git).clone.with_any_args.never
|
337
|
-
mock(@git).push_with_retry.with_any_args.times(
|
351
|
+
mock(@git).push_with_retry.with_any_args.times(2) { true }
|
338
352
|
mock(@git).is_clean_working_directory? { false }
|
353
|
+
mock(@git).did_stash_changes?.with_any_args.any_times { true }
|
354
|
+
mock(@git).branches.any_times { "master" }
|
355
|
+
mock(@git).all_branches.any_times { "master\nremotes/mortar/master" }
|
339
356
|
|
340
|
-
@git.sync_embedded_project(p, "bob-the-builder-base")
|
357
|
+
@git.sync_embedded_project(p, "bob-the-builder-base", "mortarcode-dev")
|
341
358
|
|
342
359
|
File.exists?("#{project_mirror_dir}/pigscripts/calydonian_boar.pig").should be_true
|
343
360
|
FileUtils.rm_rf(mirror_dir)
|
@@ -347,6 +364,7 @@ STASH
|
|
347
364
|
it "syncs deleted files to the project mirror" do
|
348
365
|
with_embedded_project do |p|
|
349
366
|
mirror_dir = File.join(Dir.tmpdir, "mortar", "test-git-mirror")
|
367
|
+
FileUtils.rm_rf(mirror_dir)
|
350
368
|
mock(@git).mortar_mirrors_dir.any_times { mirror_dir }
|
351
369
|
|
352
370
|
project_mirror_dir = File.join(mirror_dir, p.name)
|
@@ -355,11 +373,15 @@ STASH
|
|
355
373
|
FileUtils.touch("#{project_mirror_dir}/pigscripts/calydonian_boar.pig")
|
356
374
|
|
357
375
|
mock(@git).git.with_any_args.any_times { true }
|
376
|
+
mock(@git).remotes.with_any_args.any_times { {"origin"=> "git@github.com:mortarcode-dev/4dbbd83cae8d5bf8a4000000_#{p.name}.git"} }
|
358
377
|
mock(@git).clone.with_any_args.never
|
359
|
-
mock(@git).push_with_retry.with_any_args.times(
|
378
|
+
mock(@git).push_with_retry.with_any_args.times(2) { true }
|
360
379
|
mock(@git).is_clean_working_directory? { false }
|
380
|
+
mock(@git).did_stash_changes?.with_any_args.any_times { true }
|
381
|
+
mock(@git).branches.any_times { "master" }
|
382
|
+
mock(@git).all_branches.any_times { "master\nremotes/mortar/master" }
|
361
383
|
|
362
|
-
@git.sync_embedded_project(p, "bob-the-builder-base")
|
384
|
+
@git.sync_embedded_project(p, "bob-the-builder-base", "mortarcode-dev")
|
363
385
|
|
364
386
|
File.exists?("#{project_mirror_dir}/pigscripts/calydonian_boar.pig").should be_false
|
365
387
|
FileUtils.rm_rf(mirror_dir)
|
data/spec/spec_helper.rb
CHANGED
@@ -197,7 +197,12 @@ def with_blank_project(&block)
|
|
197
197
|
end
|
198
198
|
|
199
199
|
def with_git_initialized_project(&block)
|
200
|
-
|
200
|
+
remote_prefix = "4dbbd83cae8d5bf8a4000000_"
|
201
|
+
with_git_initialized_project_with_remote_prefix(remote_prefix, &block)
|
202
|
+
end
|
203
|
+
|
204
|
+
def with_git_initialized_project_with_remote_prefix(remote_prefix, &block)
|
205
|
+
# wrap block in a proc that does a commit
|
201
206
|
commit_proc = Proc.new do |project|
|
202
207
|
git = Mortar::Git::Git.new
|
203
208
|
git.create_mortar_project_manifest(project.root_path)
|
@@ -205,7 +210,7 @@ def with_git_initialized_project(&block)
|
|
205
210
|
remote = "mortar"
|
206
211
|
`git add .mortar-project-manifest`
|
207
212
|
`git commit -a -m "First commit"`
|
208
|
-
`git remote add #{remote} git@github.com:mortarcode-dev
|
213
|
+
`git remote add #{remote} git@github.com:mortarcode-dev/#{remote_prefix}#{project.name}.git`
|
209
214
|
project.remote = remote
|
210
215
|
block.call(project)
|
211
216
|
end
|
metadata
CHANGED
@@ -1,32 +1,36 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mortar
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.3
|
5
|
+
prerelease:
|
5
6
|
platform: ruby
|
6
7
|
authors:
|
7
8
|
- Mortar Data
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-11-
|
12
|
+
date: 2013-11-06 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: rdoc
|
15
16
|
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
16
18
|
requirements:
|
17
|
-
- - '>='
|
19
|
+
- - ! '>='
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: 4.0.0
|
20
22
|
type: :runtime
|
21
23
|
prerelease: false
|
22
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
23
26
|
requirements:
|
24
|
-
- - '>='
|
27
|
+
- - ! '>='
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 4.0.0
|
27
30
|
- !ruby/object:Gem::Dependency
|
28
31
|
name: mortar-api-ruby
|
29
32
|
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
30
34
|
requirements:
|
31
35
|
- - ~>
|
32
36
|
- !ruby/object:Gem::Version
|
@@ -34,6 +38,7 @@ dependencies:
|
|
34
38
|
type: :runtime
|
35
39
|
prerelease: false
|
36
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
37
42
|
requirements:
|
38
43
|
- - ~>
|
39
44
|
- !ruby/object:Gem::Version
|
@@ -41,6 +46,7 @@ dependencies:
|
|
41
46
|
- !ruby/object:Gem::Dependency
|
42
47
|
name: netrc
|
43
48
|
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
44
50
|
requirements:
|
45
51
|
- - ~>
|
46
52
|
- !ruby/object:Gem::Version
|
@@ -48,6 +54,7 @@ dependencies:
|
|
48
54
|
type: :runtime
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
51
58
|
requirements:
|
52
59
|
- - ~>
|
53
60
|
- !ruby/object:Gem::Version
|
@@ -55,6 +62,7 @@ dependencies:
|
|
55
62
|
- !ruby/object:Gem::Dependency
|
56
63
|
name: launchy
|
57
64
|
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
58
66
|
requirements:
|
59
67
|
- - ~>
|
60
68
|
- !ruby/object:Gem::Version
|
@@ -62,6 +70,7 @@ dependencies:
|
|
62
70
|
type: :runtime
|
63
71
|
prerelease: false
|
64
72
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
65
74
|
requirements:
|
66
75
|
- - ~>
|
67
76
|
- !ruby/object:Gem::Version
|
@@ -69,6 +78,7 @@ dependencies:
|
|
69
78
|
- !ruby/object:Gem::Dependency
|
70
79
|
name: parseconfig
|
71
80
|
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
72
82
|
requirements:
|
73
83
|
- - ~>
|
74
84
|
- !ruby/object:Gem::Version
|
@@ -76,6 +86,7 @@ dependencies:
|
|
76
86
|
type: :runtime
|
77
87
|
prerelease: false
|
78
88
|
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
79
90
|
requirements:
|
80
91
|
- - ~>
|
81
92
|
- !ruby/object:Gem::Version
|
@@ -83,20 +94,29 @@ dependencies:
|
|
83
94
|
- !ruby/object:Gem::Dependency
|
84
95
|
name: excon
|
85
96
|
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
86
98
|
requirements:
|
87
99
|
- - ~>
|
88
100
|
- !ruby/object:Gem::Version
|
89
101
|
version: '0.15'
|
102
|
+
- - <
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0.17'
|
90
105
|
type: :development
|
91
106
|
prerelease: false
|
92
107
|
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
none: false
|
93
109
|
requirements:
|
94
110
|
- - ~>
|
95
111
|
- !ruby/object:Gem::Version
|
96
112
|
version: '0.15'
|
113
|
+
- - <
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0.17'
|
97
116
|
- !ruby/object:Gem::Dependency
|
98
117
|
name: fakefs
|
99
118
|
requirement: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
100
120
|
requirements:
|
101
121
|
- - ~>
|
102
122
|
- !ruby/object:Gem::Version
|
@@ -104,6 +124,7 @@ dependencies:
|
|
104
124
|
type: :development
|
105
125
|
prerelease: false
|
106
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
107
128
|
requirements:
|
108
129
|
- - ~>
|
109
130
|
- !ruby/object:Gem::Version
|
@@ -111,57 +132,65 @@ dependencies:
|
|
111
132
|
- !ruby/object:Gem::Dependency
|
112
133
|
name: gem-release
|
113
134
|
requirement: !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
114
136
|
requirements:
|
115
|
-
- - '>='
|
137
|
+
- - ! '>='
|
116
138
|
- !ruby/object:Gem::Version
|
117
139
|
version: '0'
|
118
140
|
type: :development
|
119
141
|
prerelease: false
|
120
142
|
version_requirements: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
121
144
|
requirements:
|
122
|
-
- - '>='
|
145
|
+
- - ! '>='
|
123
146
|
- !ruby/object:Gem::Version
|
124
147
|
version: '0'
|
125
148
|
- !ruby/object:Gem::Dependency
|
126
149
|
name: rake
|
127
150
|
requirement: !ruby/object:Gem::Requirement
|
151
|
+
none: false
|
128
152
|
requirements:
|
129
|
-
- - '>='
|
153
|
+
- - ! '>='
|
130
154
|
- !ruby/object:Gem::Version
|
131
155
|
version: '0'
|
132
156
|
type: :development
|
133
157
|
prerelease: false
|
134
158
|
version_requirements: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
135
160
|
requirements:
|
136
|
-
- - '>='
|
161
|
+
- - ! '>='
|
137
162
|
- !ruby/object:Gem::Version
|
138
163
|
version: '0'
|
139
164
|
- !ruby/object:Gem::Dependency
|
140
165
|
name: rr
|
141
166
|
requirement: !ruby/object:Gem::Requirement
|
167
|
+
none: false
|
142
168
|
requirements:
|
143
|
-
- - '>='
|
169
|
+
- - ! '>='
|
144
170
|
- !ruby/object:Gem::Version
|
145
171
|
version: '0'
|
146
172
|
type: :development
|
147
173
|
prerelease: false
|
148
174
|
version_requirements: !ruby/object:Gem::Requirement
|
175
|
+
none: false
|
149
176
|
requirements:
|
150
|
-
- - '>='
|
177
|
+
- - ! '>='
|
151
178
|
- !ruby/object:Gem::Version
|
152
179
|
version: '0'
|
153
180
|
- !ruby/object:Gem::Dependency
|
154
181
|
name: rspec
|
155
182
|
requirement: !ruby/object:Gem::Requirement
|
183
|
+
none: false
|
156
184
|
requirements:
|
157
|
-
- - '>='
|
185
|
+
- - ! '>='
|
158
186
|
- !ruby/object:Gem::Version
|
159
187
|
version: '0'
|
160
188
|
type: :development
|
161
189
|
prerelease: false
|
162
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
none: false
|
163
192
|
requirements:
|
164
|
-
- - '>='
|
193
|
+
- - ! '>='
|
165
194
|
- !ruby/object:Gem::Version
|
166
195
|
version: '0'
|
167
196
|
description: Client library and command-line tool to interact with the Mortar service.
|
@@ -188,6 +217,7 @@ files:
|
|
188
217
|
- lib/mortar/command/auth.rb
|
189
218
|
- lib/mortar/command/base.rb
|
190
219
|
- lib/mortar/command/clusters.rb
|
220
|
+
- lib/mortar/command/config.rb
|
191
221
|
- lib/mortar/command/describe.rb
|
192
222
|
- lib/mortar/command/fixtures.rb
|
193
223
|
- lib/mortar/command/generate.rb
|
@@ -268,6 +298,7 @@ files:
|
|
268
298
|
- spec/mortar/command/auth_spec.rb
|
269
299
|
- spec/mortar/command/base_spec.rb
|
270
300
|
- spec/mortar/command/clusters_spec.rb
|
301
|
+
- spec/mortar/command/config_spec.rb
|
271
302
|
- spec/mortar/command/describe_spec.rb
|
272
303
|
- spec/mortar/command/fixtures_spec.rb
|
273
304
|
- spec/mortar/command/generate_spec.rb
|
@@ -294,25 +325,26 @@ files:
|
|
294
325
|
- spec/support/display_message_matcher.rb
|
295
326
|
homepage: http://mortardata.com/
|
296
327
|
licenses: []
|
297
|
-
metadata: {}
|
298
328
|
post_install_message:
|
299
329
|
rdoc_options: []
|
300
330
|
require_paths:
|
301
331
|
- lib
|
302
332
|
required_ruby_version: !ruby/object:Gem::Requirement
|
333
|
+
none: false
|
303
334
|
requirements:
|
304
|
-
- - '>='
|
335
|
+
- - ! '>='
|
305
336
|
- !ruby/object:Gem::Version
|
306
337
|
version: 1.8.7
|
307
338
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
339
|
+
none: false
|
308
340
|
requirements:
|
309
|
-
- - '>='
|
341
|
+
- - ! '>='
|
310
342
|
- !ruby/object:Gem::Version
|
311
343
|
version: '0'
|
312
344
|
requirements: []
|
313
345
|
rubyforge_project:
|
314
|
-
rubygems_version:
|
346
|
+
rubygems_version: 1.8.23
|
315
347
|
signing_key:
|
316
|
-
specification_version:
|
348
|
+
specification_version: 3
|
317
349
|
summary: Client library and CLI to interact with the Mortar service.
|
318
350
|
test_files: []
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
metadata.gz: 84498078ec4cc6f821a23903c5d3b39fbc2d7cf5
|
4
|
-
data.tar.gz: 9f066774d16608373eb6c4e73fb5117b9042ddf5
|
5
|
-
SHA512:
|
6
|
-
metadata.gz: fa8353b19c786213a84e2de3e4aacc818aca11266092655b456418eec95e7a6421a83fb26ade16bcc664fd8950aeaa84a7564fa5660f35f311b25a1a881b75a3
|
7
|
-
data.tar.gz: aafd11d89346694c04a41a77ce9abb2c30a6cf4316054901524ddc9f823a636e6962180c28340c08dec4449e24fa5d3a6c8bc9d6b79a8acd0137df6d5ea991e3
|