mortar 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/mortar/command.rb +10 -0
- data/lib/mortar/command/clusters.rb +6 -1
- data/lib/mortar/command/describe.rb +1 -3
- data/lib/mortar/command/jobs.rb +74 -34
- data/lib/mortar/command/projects.rb +35 -0
- data/lib/mortar/command/validate.rb +2 -4
- data/lib/mortar/templates/pigscript/pigscript.pig +1 -1
- data/lib/mortar/templates/project/gitignore +1 -0
- data/lib/mortar/templates/project/pigscripts/pigscript.pig +1 -1
- data/lib/mortar/version.rb +1 -1
- data/spec/mortar/command/clusters_spec.rb +1 -2
- data/spec/mortar/command/describe_spec.rb +2 -2
- data/spec/mortar/command/jobs_spec.rb +86 -9
- data/spec/mortar/command/projects_spec.rb +56 -0
- data/spec/mortar/command/validate_spec.rb +2 -2
- metadata +3 -3
data/lib/mortar/command.rb
CHANGED
@@ -128,6 +128,7 @@ module Mortar
|
|
128
128
|
def self.prepare_run(cmd, args=[])
|
129
129
|
command = parse(cmd)
|
130
130
|
|
131
|
+
|
131
132
|
if args.include?('-h') || args.include?('--help')
|
132
133
|
args.unshift(cmd) unless cmd =~ /^-.*/
|
133
134
|
cmd = 'help'
|
@@ -138,6 +139,15 @@ module Mortar
|
|
138
139
|
if %w( -v --version ).include?(cmd)
|
139
140
|
cmd = 'version'
|
140
141
|
command = parse(cmd)
|
142
|
+
# Check if the command tried matches a command file. If it does, the command exists, but doesn't have an index action
|
143
|
+
# Otherwise it would have been picked up by the original parse command.
|
144
|
+
elsif Dir[File.join(File.dirname(__FILE__), "command", "*.rb")].find { |file| file.include?(cmd) }
|
145
|
+
display "#{cmd} command requires arguments"
|
146
|
+
display
|
147
|
+
# Display the command's help message
|
148
|
+
args.unshift(cmd) unless cmd =~ /^-.*/
|
149
|
+
cmd = 'help'
|
150
|
+
command = parse('help')
|
141
151
|
else
|
142
152
|
error([
|
143
153
|
"`#{cmd}` is not a mortar command.",
|
@@ -36,8 +36,13 @@ class Mortar::Command::Clusters < Mortar::Command::Base
|
|
36
36
|
validate_arguments!
|
37
37
|
|
38
38
|
clusters = api.get_clusters().body['clusters']
|
39
|
-
|
39
|
+
if not clusters.empty?
|
40
|
+
display_table(clusters,
|
40
41
|
%w( cluster_id size status_description cluster_type_description start_timestamp duration),
|
41
42
|
['cluster_id', 'Size (# of Nodes)', 'Status', 'Type', 'Start Timestamp', 'Elapsed Time'])
|
43
|
+
else
|
44
|
+
display("There are no running or recent clusters")
|
45
|
+
end
|
46
|
+
|
42
47
|
end
|
43
48
|
end
|
@@ -66,9 +66,7 @@ class Mortar::Command::Describe < Mortar::Command::Base
|
|
66
66
|
is_finished =
|
67
67
|
Mortar::API::Describe::STATUSES_COMPLETE.include?(describe_result["status_code"])
|
68
68
|
|
69
|
-
redisplay("
|
70
|
-
describe_result['status_description'] + (is_finished ? "" : "..."),
|
71
|
-
is_finished ? " " : spinner(ticks)],
|
69
|
+
redisplay("[#{spinner(ticks)}] Calculating schema for #{alias_name} and ancestors...",
|
72
70
|
is_finished) # only display newline on last message
|
73
71
|
if is_finished
|
74
72
|
display
|
data/lib/mortar/command/jobs.rb
CHANGED
@@ -124,7 +124,7 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
124
124
|
display
|
125
125
|
display("Job status can be viewed on the web at:\n\n #{response['web_job_url']}")
|
126
126
|
display
|
127
|
-
display("Or by running:\n\n mortar jobs:status #{response['job_id']}")
|
127
|
+
display("Or by running:\n\n mortar jobs:status #{response['job_id']} --poll")
|
128
128
|
display
|
129
129
|
end
|
130
130
|
|
@@ -135,6 +135,9 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
135
135
|
#
|
136
136
|
# Check the status of a job.
|
137
137
|
#
|
138
|
+
# -p, --poll # Poll the status of a job
|
139
|
+
#
|
140
|
+
#
|
138
141
|
#Examples:
|
139
142
|
#
|
140
143
|
# $ mortar jobs:status 2000cbbba40a860a6f000000
|
@@ -149,43 +152,80 @@ class Mortar::Command::Jobs < Mortar::Command::Base
|
|
149
152
|
error("Usage: mortar jobs:status JOB_ID\nMust specify JOB_ID.")
|
150
153
|
end
|
151
154
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
155
|
+
# Inner function to display the hash table when the job is complte
|
156
|
+
def display_job_status(job_status)
|
157
|
+
job_display_entries = {
|
158
|
+
"status" => job_status["status_description"],
|
159
|
+
"progress" => "#{job_status["progress"]}%",
|
160
|
+
"cluster_id" => job_status["cluster_id"],
|
161
|
+
"job submitted at" => job_status["start_timestamp"],
|
162
|
+
"job began running at" => job_status["running_timestamp"],
|
163
|
+
"job finished at" => job_status["stop_timestamp"],
|
164
|
+
"job running for" => job_status["duration"],
|
165
|
+
"job run with parameters" => job_status["parameters"],
|
166
|
+
}
|
167
|
+
|
168
|
+
|
169
|
+
unless job_status["error"].nil? || job_status["error"]["message"].nil?
|
170
|
+
error_context = get_error_message_context(job_status["error"]["message"])
|
171
|
+
unless error_context == ""
|
172
|
+
job_status["error"]["help"] = error_context
|
173
|
+
end
|
174
|
+
job_status["error"].each_pair do |key, value|
|
175
|
+
job_display_entries["error - #{key}"] = value
|
176
|
+
end
|
170
177
|
end
|
178
|
+
|
179
|
+
if job_status["num_hadoop_jobs"] && job_status["num_hadoop_jobs_succeeded"]
|
180
|
+
job_display_entries["hadoop jobs complete"] =
|
181
|
+
'%0.2f / %0.2f' % [job_status["num_hadoop_jobs_succeeded"], job_status["num_hadoop_jobs"]]
|
182
|
+
end
|
183
|
+
|
184
|
+
if job_status["outputs"] && job_status["outputs"].length > 0
|
185
|
+
job_display_entries["outputs"] = Hash[job_status["outputs"].select{|o| o["alias"]}.collect do |output|
|
186
|
+
output_hash = {}
|
187
|
+
output_hash["location"] = output["location"] if output["location"]
|
188
|
+
output_hash["records"] = output["records"] if output["records"]
|
189
|
+
[output['alias'], output_hash]
|
190
|
+
end]
|
191
|
+
end
|
192
|
+
|
193
|
+
styled_header("#{job_status["project_name"]}: #{job_status["pigscript_name"]} (job_id: #{job_status["job_id"]})")
|
194
|
+
styled_hash(job_display_entries)
|
171
195
|
end
|
172
196
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
197
|
+
# If polling the status
|
198
|
+
if options[:poll]
|
199
|
+
ticking(polling_interval) do |ticks|
|
200
|
+
job_status = api.get_job(job_id).body
|
201
|
+
# If the job is complete exit and display the table normally
|
202
|
+
if Mortar::API::Jobs::STATUSES_COMPLETE.include?(job_status["status_code"] )
|
203
|
+
redisplay("")
|
204
|
+
display_job_status(job_status)
|
205
|
+
break
|
206
|
+
end
|
207
|
+
|
208
|
+
# If the job is running show the progress bar
|
209
|
+
if job_status["status_code"] == Mortar::API::Jobs::STATUS_RUNNING
|
210
|
+
progressbar = "=" + ("=" * (job_status["progress"].to_i / 5)) + ">"
|
211
|
+
|
212
|
+
if job_status["num_hadoop_jobs"] && job_status["num_hadoop_jobs_succeeded"]
|
213
|
+
hadoop_jobs_ratio_complete =
|
214
|
+
'%0.2f / %0.2f' % [job_status["num_hadoop_jobs_succeeded"], job_status["num_hadoop_jobs"]]
|
215
|
+
end
|
216
|
+
|
217
|
+
printf("\r[#{spinner(ticks)}] Status: [%-22s] %s%% Complete (%s MapReduce jobs finished)", progressbar, job_status["progress"], hadoop_jobs_ratio_complete)
|
218
|
+
|
219
|
+
# If the job is not complete, but not in the running state, just display its status
|
220
|
+
else
|
221
|
+
redisplay("[#{spinner(ticks)}] Status: #{job_status['status_description']}")
|
222
|
+
end
|
223
|
+
end
|
224
|
+
# If not polling, get the job status and display the results
|
225
|
+
else
|
226
|
+
job_status = api.get_job(job_id).body
|
227
|
+
display_job_status(job_status)
|
185
228
|
end
|
186
|
-
|
187
|
-
styled_header("#{job_status["project_name"]}: #{job_status["pigscript_name"]} (job_id: #{job_status["job_id"]})")
|
188
|
-
styled_hash(job_display_entries)
|
189
229
|
end
|
190
230
|
|
191
231
|
# jobs:stop JOB_ID
|
@@ -105,6 +105,41 @@ class Mortar::Command::Projects < Mortar::Command::Base
|
|
105
105
|
end
|
106
106
|
|
107
107
|
end
|
108
|
+
|
109
|
+
# projects:set_remote PROJECT
|
110
|
+
#
|
111
|
+
# Adds the Mortar remote to the local git project. This is necessary for successfully executing many of the Mortar commands.
|
112
|
+
#
|
113
|
+
#Example:
|
114
|
+
#
|
115
|
+
# $ mortar projects:set_remote my_project
|
116
|
+
#
|
117
|
+
def set_remote
|
118
|
+
project_name = shift_argument
|
119
|
+
|
120
|
+
unless project_name
|
121
|
+
error("Usage: mortar projects:set_remote PROJECT\nMust specify PROJECT.")
|
122
|
+
end
|
123
|
+
|
124
|
+
unless git.has_dot_git?
|
125
|
+
error("Can only set the remote for an existing git project. Please run:\n\ngit init\ngit add .\ngit commit -a -m \"first commit\"\n\nto initialize your project in git.")
|
126
|
+
end
|
127
|
+
|
128
|
+
if git.remotes(git_organization).include?("mortar")
|
129
|
+
display("The remote has already been set for project: #{project_name}")
|
130
|
+
return
|
131
|
+
end
|
132
|
+
|
133
|
+
projects = api.get_projects().body["projects"]
|
134
|
+
project = projects.find { |p| p['name'] == project_name}
|
135
|
+
unless project
|
136
|
+
error("No project named: #{project_name} exists. You can create this project using:\n\n mortar projects:create")
|
137
|
+
end
|
138
|
+
|
139
|
+
git.remote_add("mortar", project['git_url'])
|
140
|
+
display("Successfully added the mortar remote to the #{project_name} project")
|
141
|
+
|
142
|
+
end
|
108
143
|
|
109
144
|
# projects:clone PROJECT
|
110
145
|
#
|
@@ -66,10 +66,8 @@ class Mortar::Command::Validate < Mortar::Command::Base
|
|
66
66
|
validate_result = api.get_validate(validate_id).body
|
67
67
|
is_finished =
|
68
68
|
Mortar::API::Validate::STATUSES_COMPLETE.include?(validate_result["status_code"])
|
69
|
-
|
70
|
-
redisplay("
|
71
|
-
validate_result['status_description'] + (is_finished ? "" : "..."),
|
72
|
-
is_finished ? " " : spinner(ticks)],
|
69
|
+
|
70
|
+
redisplay("[#{spinner(ticks)}] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access",
|
73
71
|
is_finished) # only display newline on last message
|
74
72
|
if is_finished
|
75
73
|
display
|
@@ -12,7 +12,7 @@
|
|
12
12
|
* User-Defined Functions (UDFs)
|
13
13
|
*/
|
14
14
|
|
15
|
-
REGISTER '../udfs/python/<%= script_name %>.py'
|
15
|
+
REGISTER '../udfs/python/<%= script_name %>.py' USING streaming_python AS <%= script_name %>;
|
16
16
|
<% end %>
|
17
17
|
|
18
18
|
-- This is an example of loading up input data
|
@@ -10,7 +10,7 @@
|
|
10
10
|
/**
|
11
11
|
* User-Defined Functions (UDFs)
|
12
12
|
*/
|
13
|
-
REGISTER '../udfs/python/<%= project_name %>.py'
|
13
|
+
REGISTER '../udfs/python/<%= project_name %>.py' USING streaming_python AS <%= project_name %>;
|
14
14
|
|
15
15
|
-- This is an example of loading up input data
|
16
16
|
my_input_data = LOAD '$INPUT_PATH'
|
data/lib/mortar/version.rb
CHANGED
@@ -52,8 +52,7 @@ STDOUT
|
|
52
52
|
mock(Mortar::Auth.api).get_clusters().returns(Excon::Response.new(:body => {"clusters" => []}))
|
53
53
|
stderr, stdout = execute("clusters", nil, nil)
|
54
54
|
stdout.should == <<-STDOUT
|
55
|
-
|
56
|
-
---------- ----------------- ------ ---- --------------- ------------
|
55
|
+
There are no running or recent clusters
|
57
56
|
STDOUT
|
58
57
|
end
|
59
58
|
end
|
@@ -86,7 +86,7 @@ Taking code snapshot... done
|
|
86
86
|
Sending code snapshot to Mortar... done
|
87
87
|
Starting describe... done
|
88
88
|
|
89
|
-
\r\e[
|
89
|
+
\r\e[0K[/] Calculating schema for my_alias and ancestors...\r\e[0K[-] Calculating schema for my_alias and ancestors...\r\e[0K[\\] Calculating schema for my_alias and ancestors...\r\e[0K[|] Calculating schema for my_alias and ancestors...
|
90
90
|
|
91
91
|
Results available at https://api.mortardata.com/describe/c571a8c7f76a4fd4a67c103d753e2dd5
|
92
92
|
Opening web browser to show results... done
|
@@ -119,7 +119,7 @@ Taking code snapshot... done
|
|
119
119
|
Sending code snapshot to Mortar... done
|
120
120
|
Starting describe... done
|
121
121
|
|
122
|
-
\r\e[
|
122
|
+
\r\e[0K[/] Calculating schema for my_alias and ancestors...\r\e[0K[-] Calculating schema for my_alias and ancestors...
|
123
123
|
|
124
124
|
STDOUT
|
125
125
|
stderr.should == <<-STDERR
|
@@ -56,7 +56,7 @@ Job status can be viewed on the web at:
|
|
56
56
|
|
57
57
|
Or by running:
|
58
58
|
|
59
|
-
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5
|
59
|
+
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5 --poll
|
60
60
|
|
61
61
|
STDOUT
|
62
62
|
end
|
@@ -87,7 +87,7 @@ Job status can be viewed on the web at:
|
|
87
87
|
|
88
88
|
Or by running:
|
89
89
|
|
90
|
-
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5
|
90
|
+
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5 --poll
|
91
91
|
|
92
92
|
STDOUT
|
93
93
|
end
|
@@ -116,7 +116,7 @@ Job status can be viewed on the web at:
|
|
116
116
|
|
117
117
|
Or by running:
|
118
118
|
|
119
|
-
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5
|
119
|
+
mortar jobs:status c571a8c7f76a4fd4a67c103d753e2dd5 --poll
|
120
120
|
|
121
121
|
STDOUT
|
122
122
|
end
|
@@ -339,11 +339,10 @@ STDOUT
|
|
339
339
|
stdout.should == <<-STDOUT
|
340
340
|
=== myproject: my_script (job_id: c571a8c7f76a4fd4a67c103d753e2dd5)
|
341
341
|
cluster_id: e2790e7e8c7d48e39157238d58191346
|
342
|
-
error:
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
type: RuntimeError
|
342
|
+
error - column_number: 34
|
343
|
+
error - line_number: 43
|
344
|
+
error - message: An error occurred and here's some more info
|
345
|
+
error - type: RuntimeError
|
347
346
|
hadoop jobs complete: 0.00 / 4.00
|
348
347
|
job began running at: 2012-02-28T03:41:52.613000+00:00
|
349
348
|
job finished at: 2012-02-28T03:45:52.613000+00:00
|
@@ -354,6 +353,85 @@ job running for: 6 mins
|
|
354
353
|
job submitted at: 2012-02-28T03:35:42.831000+00:00
|
355
354
|
progress: 55%
|
356
355
|
status: Execution error
|
356
|
+
STDOUT
|
357
|
+
end
|
358
|
+
end
|
359
|
+
it "gets status for a running job using polling" do
|
360
|
+
with_git_initialized_project do |p|
|
361
|
+
job_id = "c571a8c7f76a4fd4a67c103d753e2dd5"
|
362
|
+
pigscript_name = "my_script"
|
363
|
+
project_name = "myproject"
|
364
|
+
status_code = Mortar::API::Jobs::STATUS_RUNNING
|
365
|
+
progress = 0
|
366
|
+
cluster_id = "e2790e7e8c7d48e39157238d58191346"
|
367
|
+
start_timestamp = "2012-02-28T03:35:42.831000+00:00"
|
368
|
+
stop_timestamp = "2012-02-28T03:44:52.613000+00:00"
|
369
|
+
running_timestamp = "2012-02-28T03:41:52.613000+00:00"
|
370
|
+
parameters = {"my_param_1" => "value1", "MY_PARAM_2" => "3"}
|
371
|
+
|
372
|
+
mock(Mortar::Auth.api).get_job(job_id).returns(Excon::Response.new(:body => {"job_id" => job_id,
|
373
|
+
"pigscript_name" => pigscript_name,
|
374
|
+
"project_name" => project_name,
|
375
|
+
"status_code" => status_code,
|
376
|
+
"status_description" => "Execution error",
|
377
|
+
"progress" => progress,
|
378
|
+
"cluster_id" => cluster_id,
|
379
|
+
"start_timestamp" => start_timestamp,
|
380
|
+
"running_timestamp" => running_timestamp,
|
381
|
+
"duration" => "6 mins",
|
382
|
+
"num_hadoop_jobs" => 4,
|
383
|
+
"num_hadoop_jobs_succeeded" => 0,
|
384
|
+
"parameters" => parameters
|
385
|
+
}))
|
386
|
+
|
387
|
+
status_code = Mortar::API::Jobs::STATUS_SUCCESS
|
388
|
+
progress = 100
|
389
|
+
outputs = [{'name'=> 'hottest_songs_of_the_decade',
|
390
|
+
'records' => 10,
|
391
|
+
'alias' => 'output_data',
|
392
|
+
'location' => 's3n://my-bucket/my-folder/hottest_songs_of_the_decade/output_data'},
|
393
|
+
{'name'=> 'hottest_songs_of_the_decade',
|
394
|
+
'records' => 100,
|
395
|
+
'alias' => 'output_data_2',
|
396
|
+
'location' => 's3n://my-bucket/my-folder/hottest_songs_of_the_decade/output_data_2'}]
|
397
|
+
|
398
|
+
mock(Mortar::Auth.api).get_job(job_id).returns(Excon::Response.new(:body => {"job_id" => job_id,
|
399
|
+
"pigscript_name" => pigscript_name,
|
400
|
+
"project_name" => project_name,
|
401
|
+
"status_code" => status_code,
|
402
|
+
"status_description" => "Success",
|
403
|
+
"progress" => progress,
|
404
|
+
"cluster_id" => cluster_id,
|
405
|
+
"start_timestamp" => start_timestamp,
|
406
|
+
"running_timestamp" => running_timestamp,
|
407
|
+
"stop_timestamp" => stop_timestamp,
|
408
|
+
"duration" => "6 mins",
|
409
|
+
"num_hadoop_jobs" => 4,
|
410
|
+
"num_hadoop_jobs_succeeded" => 4,
|
411
|
+
"parameters" => parameters,
|
412
|
+
"outputs" => outputs
|
413
|
+
}))
|
414
|
+
stderr, stdout = execute("jobs:status c571a8c7f76a4fd4a67c103d753e2dd5 -p", p, @git)
|
415
|
+
stdout.should == <<-STDOUT
|
416
|
+
\r[/] Status: [=> ] 0% Complete (0.00 / 4.00 MapReduce jobs finished)\r\e[0K=== myproject: my_script (job_id: c571a8c7f76a4fd4a67c103d753e2dd5)
|
417
|
+
cluster_id: e2790e7e8c7d48e39157238d58191346
|
418
|
+
hadoop jobs complete: 4.00 / 4.00
|
419
|
+
job began running at: 2012-02-28T03:41:52.613000+00:00
|
420
|
+
job finished at: 2012-02-28T03:44:52.613000+00:00
|
421
|
+
job run with parameters:
|
422
|
+
MY_PARAM_2: 3
|
423
|
+
my_param_1: value1
|
424
|
+
job running for: 6 mins
|
425
|
+
job submitted at: 2012-02-28T03:35:42.831000+00:00
|
426
|
+
outputs:
|
427
|
+
output_data:
|
428
|
+
location: s3n://my-bucket/my-folder/hottest_songs_of_the_decade/output_data
|
429
|
+
records: 10
|
430
|
+
output_data_2:
|
431
|
+
location: s3n://my-bucket/my-folder/hottest_songs_of_the_decade/output_data_2
|
432
|
+
records: 100
|
433
|
+
progress: 100%
|
434
|
+
status: Success
|
357
435
|
STDOUT
|
358
436
|
end
|
359
437
|
end
|
@@ -380,7 +458,6 @@ STDOUT
|
|
380
458
|
|
381
459
|
|
382
460
|
end
|
383
|
-
|
384
461
|
end
|
385
462
|
end
|
386
463
|
end
|
@@ -129,6 +129,62 @@ STDOUT
|
|
129
129
|
end
|
130
130
|
|
131
131
|
end
|
132
|
+
|
133
|
+
context("set_remote") do
|
134
|
+
|
135
|
+
it "sets the remote of a project" do
|
136
|
+
with_git_initialized_project do |p|
|
137
|
+
project_name = p.name
|
138
|
+
project_git_url = "git@github.com:mortarcode-dev/#{project_name}"
|
139
|
+
`git remote rm mortar`
|
140
|
+
mock(Mortar::Auth.api).get_projects().returns(Excon::Response.new(:body => {"projects" => [ { "name" => project_name, "status" => Mortar::API::Projects::STATUS_ACTIVE, "git_url" => project_git_url } ] })).ordered
|
141
|
+
|
142
|
+
mock(@git).remote_add("mortar", project_git_url)
|
143
|
+
|
144
|
+
stderr, stdout = execute("projects:set_remote #{project_name}", p, @git)
|
145
|
+
stdout.should == <<-STDOUT
|
146
|
+
Successfully added the mortar remote to the myproject project
|
147
|
+
STDOUT
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it "remote already added" do
|
152
|
+
with_git_initialized_project do |p|
|
153
|
+
project_name = p.name
|
154
|
+
|
155
|
+
stderr, stdout = execute("projects:set_remote #{project_name}", p, @git)
|
156
|
+
stdout.should == <<-STDERR
|
157
|
+
The remote has already been set for project: myproject
|
158
|
+
STDERR
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
it "No project given" do
|
163
|
+
with_git_initialized_project do |p|
|
164
|
+
stderr, stdout = execute("projects:set_remote", p, @git)
|
165
|
+
stderr.should == <<-STDERR
|
166
|
+
! Usage: mortar projects:set_remote PROJECT
|
167
|
+
! Must specify PROJECT.
|
168
|
+
STDERR
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
it "No project with that name" do
|
173
|
+
with_git_initialized_project do |p|
|
174
|
+
project_name = p.name
|
175
|
+
project_git_url = "git@github.com:mortarcode-dev/#{project_name}"
|
176
|
+
mock(Mortar::Auth.api).get_projects().returns(Excon::Response.new(:body => {"projects" => [ { "name" => "derp", "status" => Mortar::API::Projects::STATUS_ACTIVE, "git_url" => project_git_url } ] })).ordered
|
177
|
+
`git remote rm mortar`
|
178
|
+
|
179
|
+
stderr, stdout = execute("projects:set_remote #{project_name}", p, @git)
|
180
|
+
stderr.should == <<-STDERR
|
181
|
+
! No project named: myproject exists. You can create this project using:
|
182
|
+
!
|
183
|
+
! mortar projects:create
|
184
|
+
STDERR
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
132
188
|
|
133
189
|
|
134
190
|
context("clone") do
|
@@ -71,7 +71,7 @@ Taking code snapshot... done
|
|
71
71
|
Sending code snapshot to Mortar... done
|
72
72
|
Starting validate... done
|
73
73
|
|
74
|
-
\r\e[
|
74
|
+
\r\e[0K[/] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access\r\e[0K[-] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access\r\e[0K[\\] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access\r\e[0K[|] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access
|
75
75
|
|
76
76
|
Your script is valid.
|
77
77
|
STDOUT
|
@@ -103,7 +103,7 @@ Taking code snapshot... done
|
|
103
103
|
Sending code snapshot to Mortar... done
|
104
104
|
Starting validate... done
|
105
105
|
|
106
|
-
\r\e[
|
106
|
+
\r\e[0K[/] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access\r\e[0K[-] Checking your script for problems with: Pig syntax, Python syntax, and S3 data access
|
107
107
|
|
108
108
|
STDOUT
|
109
109
|
stderr.should == <<-STDERR
|
metadata
CHANGED