xcodebuild-rb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -16,5 +16,5 @@ module XcodeBuild
16
16
  end
17
17
  end
18
18
 
19
- require_relative "translations/building"
20
- require_relative "translations/cleaning"
19
+ require "xcode_build/translations/building"
20
+ require "xcode_build/translations/cleaning"
@@ -8,8 +8,8 @@ module XcodeBuild
8
8
 
9
9
  return unless building?
10
10
 
11
- if line =~ /^\*\* BUILD (\w+) \*\*/
12
- notify_build_ended($1)
11
+ if line =~ /^\*\* (BUILD|ARCHIVE) (\w+) \*\*/
12
+ notify_build_ended($1, $2)
13
13
  return
14
14
  end
15
15
 
@@ -30,6 +30,10 @@ module XcodeBuild
30
30
  case line
31
31
  when /^(.*):(\d+):(\d+): error: (.*)$/
32
32
  notify_build_error($1, $2, $3, $4)
33
+ when /^\s+setenv (\w+) (.*)/
34
+ notify_env_var($1, $2)
35
+ when /^Command (.*) failed with exit code (\d+)/
36
+ notify_build_step_command_failed($1, $2)
33
37
  when /^The following build commands failed:/
34
38
  @beginning_error_report = true
35
39
  when /^\n/
@@ -57,42 +61,50 @@ module XcodeBuild
57
61
  default = false
58
62
  end
59
63
 
60
- notify_delegate(:build_started, required: true, args: [{
61
- target: target,
62
- project: project,
63
- configuration: configuration,
64
- default: default
64
+ notify_delegate(:build_started, :required => true, :args => [{
65
+ :target => target,
66
+ :project => project,
67
+ :configuration => configuration,
68
+ :default => default
65
69
  }])
66
70
  end
67
71
 
68
72
  def notify_build_step(line)
69
- notify_delegate(:build_step, args: [build_step_from_line(line)])
73
+ notify_delegate(:build_step, :args => [build_step_from_line(line)])
70
74
  end
71
75
 
72
76
  def notify_build_error(file, line, char, message)
73
- notify_delegate(:build_error_detected, args: [{
74
- file: file,
75
- line: line.to_i,
76
- char: char.to_i,
77
- message: message
77
+ notify_delegate(:build_error_detected, :args => [{
78
+ :file => file,
79
+ :line => line.to_i,
80
+ :char => char.to_i,
81
+ :message => message
78
82
  }])
79
83
  end
84
+
85
+ def notify_build_step_command_failed(command, exit_code)
86
+ notify_delegate(:build_error_detected, :args => [{:command => command, :exit_code => exit_code.to_i}])
87
+ end
80
88
 
81
- def notify_build_ended(result)
89
+ def notify_build_ended(archive_or_build, result)
82
90
  if result =~ /SUCCEEDED/
83
- notify_delegate(:build_succeeded, required: true)
91
+ notify_delegate(:build_succeeded, :args => [archive_or_build], :required => true)
84
92
  else
85
- notify_delegate(:build_failed, required: true)
93
+ notify_delegate(:build_failed, :args => [archive_or_build], :required => true)
86
94
  end
87
95
  end
88
96
 
89
97
  def notify_build_step_failed(line)
90
- notify_delegate(:build_step_failed, args: [build_step_from_line(line)])
98
+ notify_delegate(:build_step_failed, :args => [build_step_from_line(line)])
99
+ end
100
+
101
+ def notify_env_var(key, value)
102
+ notify_delegate(:build_env_variable_detected, :args => [key, value])
91
103
  end
92
104
 
93
105
  def build_step_from_line(line)
94
106
  parts = line.strip.split(" ")
95
- {type: parts.shift, arguments: parts}
107
+ {:type => parts.shift, :arguments => parts}
96
108
  end
97
109
  end
98
110
 
@@ -57,37 +57,37 @@ module XcodeBuild
57
57
  default = false
58
58
  end
59
59
 
60
- notify_delegate(:clean_started, required: true, args: [{
61
- target: target,
62
- project: project,
63
- configuration: configuration,
64
- default: default
60
+ notify_delegate(:clean_started, :required => true, :args => [{
61
+ :target => target,
62
+ :project => project,
63
+ :configuration => configuration,
64
+ :default => default
65
65
  }])
66
66
  end
67
67
 
68
68
  def notify_clean_step(line)
69
- notify_delegate(:clean_step, args: [clean_step_from_line(line)])
69
+ notify_delegate(:clean_step, :args => [clean_step_from_line(line)])
70
70
  end
71
71
 
72
72
  def notify_clean_step_failed(line)
73
- notify_delegate(:clean_step_failed, args: [clean_step_from_line(line)])
73
+ notify_delegate(:clean_step_failed, :args => [clean_step_from_line(line)])
74
74
  end
75
75
 
76
76
  def notify_clean_error(message)
77
- notify_delegate(:clean_error_detected, args: [{message: message}])
77
+ notify_delegate(:clean_error_detected, :args => [{:message => message}])
78
78
  end
79
79
 
80
80
  def notify_clean_ended(result)
81
81
  if result =~ /SUCCEEDED/
82
- notify_delegate(:clean_succeeded, required: true)
82
+ notify_delegate(:clean_succeeded, :required => true)
83
83
  else
84
- notify_delegate(:clean_failed, required: true)
84
+ notify_delegate(:clean_failed, :required => true)
85
85
  end
86
86
  end
87
87
 
88
88
  def clean_step_from_line(line)
89
89
  parts = line.strip.split(" ")
90
- {type: parts.shift, arguments: parts}
90
+ {:type => parts.shift, :arguments => parts}
91
91
  end
92
92
  end
93
93
 
data/lib/xcodebuild.rb CHANGED
@@ -1 +1 @@
1
- require_relative 'xcode_build'
1
+ require 'xcode_build'
@@ -13,12 +13,17 @@ describe XcodeBuild::Tasks::BuildTask do
13
13
  XcodeBuild::Tasks::BuildTask.new(:test)
14
14
  Rake::Task["test:build"].should be_instance_of(Rake::Task)
15
15
  end
16
-
16
+
17
+ it "defines an archive task" do
18
+ XcodeBuild::Tasks::BuildTask.new
19
+ Rake::Task["xcode:archive"].should be_instance_of(Rake::Task)
20
+ end
21
+
17
22
  it "defines a clean task" do
18
23
  XcodeBuild::Tasks::BuildTask.new
19
24
  Rake::Task["xcode:clean"].should be_instance_of(Rake::Task)
20
25
  end
21
-
26
+
22
27
  it "defines a cleanbuild" do
23
28
  XcodeBuild::Tasks::BuildTask.new
24
29
  Rake::Task["xcode:cleanbuild"].should be_instance_of(Rake::Task)
@@ -68,71 +73,174 @@ describe XcodeBuild::Tasks::BuildTask do
68
73
  end
69
74
  end
70
75
 
71
- context "build task" do
72
- it "runs xcodebuild with the configured build_opts" do
73
- task = XcodeBuild::Tasks::BuildTask.new do |task|
74
- task.project_name = "TestProject.xcproject"
75
- task.configuration = "Debug"
76
- end
77
-
78
- XcodeBuild.should_receive(:run).with(task.build_opts.join(" "), anything())
79
- task.run(:build)
80
- end
81
-
82
- it "defaults to outputting the raw output to STDOUT" do
83
- task = XcodeBuild::Tasks::BuildTask.new
84
- XcodeBuild.should_receive(:run).with(anything(), STDOUT)
85
- task.run(:build)
76
+ shared_examples_for "any task" do
77
+ it "directs xcodebuild output into the translator" do
78
+ task = XcodeBuild::Tasks::BuildTask.new { |t| t.scheme = 'TestScheme' }
79
+ XcodeBuild.should_receive(:run).with(anything, instance_of(XcodeBuild::OutputTranslator)).and_return(0)
80
+ task.run(task_name)
86
81
  end
87
-
88
- it "uses a custom output buffer if specified" do
82
+
83
+ it "uses a custom output buffer if specified and a formatter has not been set" do
89
84
  buffer = stub('output buffer')
90
85
  task = XcodeBuild::Tasks::BuildTask.new do |t|
86
+ t.formatter = nil
91
87
  t.output_to = buffer
88
+ t.scheme = 'TestScheme'
92
89
  end
93
- XcodeBuild.should_receive(:run).with(anything(), buffer)
94
- task.run(:build)
90
+ task.reporter.should_receive(:direct_raw_output_to=).with(buffer)
91
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
92
+ task.run(task_name)
95
93
  end
96
-
97
- it "outputs the translator delegating to the reporter if formatter is set" do
98
- formatter = stub('formatter')
94
+
95
+ it "ignores the value of output_to if a formatter has been set" do
99
96
  task = XcodeBuild::Tasks::BuildTask.new do |t|
100
- t.formatter = formatter
97
+ t.formatter = stub('formatter')
98
+ t.output_to = stub('output buffer')
99
+ t.scheme = 'TestScheme'
101
100
  end
102
- XcodeBuild.should_receive(:run).with(anything(),
103
- output_translator_delegating_to(instance_of(XcodeBuild::Reporter)))
104
- task.run(:build)
101
+ task.reporter.should_not_receive(:direct_raw_output_to=).with(anything)
102
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
103
+ task.run(task_name)
105
104
  end
106
-
105
+
106
+ it "raises if xcodebuild returns a non-zero exit code" do
107
+ task = XcodeBuild::Tasks::BuildTask.new { |t| t.scheme = 'TestScheme' }
108
+ XcodeBuild.stub(:run).with(anything, anything).and_return(99)
109
+ lambda { task.run(task_name) }.should raise_error
110
+ end
111
+
107
112
  it "changes directory if invoke_from_within is set" do
108
113
  task = XcodeBuild::Tasks::BuildTask.new do |task|
109
114
  task.invoke_from_within = "foo/bar"
115
+ task.scheme = 'TestScheme'
110
116
  end
111
-
117
+
112
118
  Dir.should_receive(:chdir).with("foo/bar").and_yield
113
- XcodeBuild.should_receive(:run)
114
- task.run(:build)
119
+ XcodeBuild.should_receive(:run).and_return(0)
120
+ task.run(task_name)
115
121
  end
116
122
  end
117
-
123
+
124
+ shared_examples_for "build task" do
125
+ it "runs xcodebuild with the configured build_opts" do
126
+ @task = XcodeBuild::Tasks::BuildTask.new do |task|
127
+ task.project_name = "TestProject.xcproject"
128
+ task.configuration = "Debug"
129
+ task.scheme = 'TestScheme'
130
+ end
131
+
132
+ XcodeBuild.should_receive(:run).with(build_opts.join(" "), anything).and_return(0)
133
+ @task.run(task_name)
134
+ end
135
+
136
+ it "calls the after_build block after running successfully, passing in the build object from the report" do
137
+ received_build = nil
138
+
139
+ @task = XcodeBuild::Tasks::BuildTask.new do |task|
140
+ task.scheme = 'TestProject'
141
+ task.after_build do |build|
142
+ received_build = build
143
+ end
144
+ end
145
+
146
+ @task.reporter.stub(:build).and_return(expected_build = stub('build', :failed? => false))
147
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
148
+
149
+ @task.run(task_name)
150
+
151
+ received_build.should == expected_build
152
+ end
153
+
154
+ it "raises if the build has failed, even though xcodebuild returned a zero exit code" do
155
+ @task = XcodeBuild::Tasks::BuildTask.new
156
+
157
+ @task.reporter.stub(:build).and_return(stub('build', :failed? => true))
158
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
159
+
160
+ lambda { @task.run(task_name) }.should raise_error
161
+ end
162
+ end
163
+
164
+ context "build task" do
165
+ let(:task_name) { :build }
166
+ let(:build_opts) { @task.build_opts + ['build'] }
167
+
168
+ it_behaves_like "any task"
169
+ it_behaves_like "build task"
170
+ end
171
+
172
+ context "archive task" do
173
+ let(:task_name) { :archive }
174
+ let(:build_opts) { @task.build_opts + ['archive'] }
175
+
176
+ it_behaves_like "any task"
177
+ it_behaves_like "build task"
178
+
179
+ it "raises if no scheme is specified" do
180
+ task = XcodeBuild::Tasks::BuildTask.new
181
+ lambda { task.run(:archive) }.should raise_error
182
+ end
183
+
184
+ it "calls the after_archive block after running successfully, passing in the build object from the report" do
185
+ received_build = nil
186
+
187
+ @task = XcodeBuild::Tasks::BuildTask.new do |task|
188
+ task.scheme = 'TestProject'
189
+ task.after_archive do |build|
190
+ received_build = build
191
+ end
192
+ end
193
+
194
+ @task.reporter.stub(:build).and_return(expected_build = stub('build', :failed? => false))
195
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
196
+
197
+ @task.run(task_name)
198
+
199
+ received_build.should == expected_build
200
+ end
201
+ end
202
+
118
203
  context "clean task" do
204
+ let(:task_name) { :clean }
205
+
206
+ it_behaves_like "any task"
207
+
119
208
  it "runs xcodebuild with the 'clean' action" do
120
209
  task = XcodeBuild::Tasks::BuildTask.new
121
- XcodeBuild.should_receive(:run).with("clean", anything())
210
+ XcodeBuild.should_receive(:run).with("clean", anything).and_return(0)
122
211
  task.run(:clean)
123
212
  end
213
+
214
+ it "calls the after_clean block after running successfully, passing in the clean object from the report" do
215
+ received_clean = nil
216
+
217
+ @task = XcodeBuild::Tasks::BuildTask.new do |task|
218
+ task.scheme = 'TestProject'
219
+ task.after_clean do |clean|
220
+ received_clean = clean
221
+ end
222
+ end
223
+
224
+ @task.reporter.stub(:clean).and_return(expected_clean = stub('clean', :failed? => false))
225
+ XcodeBuild.stub(:run).with(anything, anything).and_return(0)
226
+
227
+ @task.run(task_name)
228
+
229
+ received_clean.should == expected_clean
230
+ end
124
231
  end
125
-
232
+
126
233
  context "cleanbuild task" do
127
234
  it "runs the clean task and then the build task" do
128
235
  task = XcodeBuild::Tasks::BuildTask.new
129
- XcodeBuild.should_receive(:run).with("clean", anything()) do
130
- XcodeBuild.should_receive(:run).with("", anything())
131
- end
236
+
237
+ XcodeBuild.should_receive(:run).with("clean", anything).ordered.and_return(0)
238
+ XcodeBuild.should_receive(:run).with("build", anything).ordered.and_return(0)
239
+
132
240
  task.run(:cleanbuild)
133
241
  end
134
242
  end
135
-
243
+
136
244
  RSpec::Matchers.define :output_translator_delegating_to do |expected|
137
245
  match do |actual|
138
246
  actual.should be_instance_of(XcodeBuild::OutputTranslator)
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe XcodeBuild::OutputTranslator do
4
4
  let(:delegate) { mock('delegate') }
5
- let(:translator) { XcodeBuild::OutputTranslator.new(delegate, ignore_global_translations: true) }
5
+ let(:translator) { XcodeBuild::OutputTranslator.new(delegate, :ignore_global_translations => true) }
6
6
 
7
7
  it "notifies the delegate of each line received (to assist additional processing elsewhere)" do
8
8
  delegate.should_receive(:beginning_translation_of_line).with("the line")
@@ -82,7 +82,7 @@ describe XcodeBuild::Reporting::BuildReporting do
82
82
 
83
83
  delegate.should_receive(:build_step_finished).with reporter.build.last_step
84
84
 
85
- event({:build_succeeded=>{}})
85
+ event({:build_succeeded=>["BUILD"]})
86
86
  end
87
87
 
88
88
  it "notifies it's delegate when the last build step finishes and the build fails" do
@@ -96,19 +96,62 @@ describe XcodeBuild::Reporting::BuildReporting do
96
96
 
97
97
  delegate.should_receive(:build_step_finished).with reporter.build.last_step
98
98
 
99
- event({:build_succeeded=>{}})
99
+ event({:build_succeeded=>["BUILD"]})
100
+ end
101
+
102
+ it "associates build errors with the right build step" do
103
+ assume_build_started
104
+
105
+ event({:build_step=>
106
+ {:type=>"CompileC",
107
+ :arguments=>
108
+ ["build/ExampleProject.build/Release-iphoneos/ExampleProject.build/Objects-normal/armv7/main.o",
109
+ "ExampleProject/AppDelegate.m",
110
+ "normal",
111
+ "armv7",
112
+ "objective-c",
113
+ "com.apple.compilers.llvm.clang.1_0.compiler"]}})
114
+
115
+ event({:build_error_detected=>
116
+ {:file=>
117
+ "/Users/luke/Code/mine/xcodebuild/resources/ExampleProject/ExampleProject/main.m",
118
+ :line=>16,
119
+ :char=>42,
120
+ :message=>"expected ';' after expression [1]"}})
121
+
122
+ reporter.build.last_step.should have(1).errors
123
+ end
124
+
125
+ it "associates build step command errors with the right build step" do
126
+ assume_build_started
127
+
128
+ event({:build_step=>
129
+ {:type=>"CompileC",
130
+ :arguments=>
131
+ ["build/ExampleProject.build/Release-iphoneos/ExampleProject.build/Objects-normal/armv7/main.o",
132
+ "ExampleProject/AppDelegate.m",
133
+ "normal",
134
+ "armv7",
135
+ "objective-c",
136
+ "com.apple.compilers.llvm.clang.1_0.compiler"]}})
137
+
138
+ event({:build_error_detected=>
139
+ {:command => "/bin/sh",
140
+ :exit_code => 1}})
141
+
142
+ reporter.build.last_step.should have(1).errors
100
143
  end
101
144
 
102
145
  it "notifies it's delegate that the build has finished when it is successful" do
103
146
  assume_build_started
104
147
  delegate.should_receive(:build_finished).with(reporter.build)
105
- event({:build_succeeded=>{}})
148
+ event({:build_succeeded=>["BUILD"]})
106
149
  end
107
150
 
108
151
  it "notifies it's delegate that the build has finished when it fails" do
109
152
  assume_build_started
110
153
  delegate.should_receive(:build_finished).with(reporter.build)
111
- event({:build_failed=>{}})
154
+ event({:build_failed=>["BUILD"]})
112
155
  end
113
156
 
114
157
  it "tracks the time a build takes" do
@@ -120,12 +163,18 @@ describe XcodeBuild::Reporting::BuildReporting do
120
163
  :default=>true}})
121
164
 
122
165
  Timecop.travel(Chronic.parse("5 seconds from now")) do
123
- event({:build_succeeded=>{}})
166
+ event({:build_succeeded=>["BUILD"]})
124
167
  end
125
168
  end
126
169
 
127
170
  reporter.build.duration.should be_within(0.01).of(5)
128
171
  end
172
+
173
+ it "tracks any environment variables reported by the build" do
174
+ assume_build_started
175
+ event({:build_env_variable_detected=>["TEST_AFTER_BUILD", "YES"]})
176
+ reporter.build.environment["TEST_AFTER_BUILD"].should == "YES"
177
+ end
129
178
  end
130
179
 
131
180
  context "once a build has started" do
@@ -176,7 +225,7 @@ describe XcodeBuild::Reporting::BuildReporting do
176
225
  "objective-c",
177
226
  "com.apple.compilers.llvm.clang.1_0.compiler"]}})
178
227
 
179
- event({:build_succeeded=>{}})
228
+ event({:build_succeeded=>["BUILD"]})
180
229
  end
181
230
 
182
231
  it_behaves_like "any build"
@@ -233,7 +282,7 @@ describe XcodeBuild::Reporting::BuildReporting do
233
282
  "objective-c",
234
283
  "com.apple.compilers.llvm.clang.1_0.compiler"]}})
235
284
 
236
- event({:build_failed=>{}})
285
+ event({:build_failed=>["BUILD"]})
237
286
 
238
287
  event({:build_step_failed=>
239
288
  {:type=>"CompileC",
@@ -289,7 +338,11 @@ describe XcodeBuild::Reporting::BuildReporting do
289
338
  params = event_data.values.first
290
339
 
291
340
  if params.any?
292
- reporter.send(message, params)
341
+ if params.is_a?(Hash)
342
+ reporter.send(message, params)
343
+ else
344
+ reporter.send(message, *params)
345
+ end
293
346
  else
294
347
  reporter.send(message)
295
348
  end