xcodebuild-rb 0.1.0 → 0.2.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.
@@ -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