xcoder 0.0.17 → 0.0.18

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/Gemfile CHANGED
@@ -1,4 +1,5 @@
1
1
  source "http://rubygems.org"
2
2
 
3
3
  gemspec
4
- gem 'rspec'
4
+ gem 'rspec'
5
+ gem 'builder'
data/bin/xcoder-build CHANGED
File without changes
data/lib/xcode/builder.rb CHANGED
@@ -1,9 +1,11 @@
1
1
  require 'xcode/shell'
2
2
  require 'xcode/provisioning_profile'
3
+ require 'xcode/test/report_parser.rb'
4
+ require 'xcode/testflight'
3
5
 
4
6
  module Xcode
5
7
  class Builder
6
- attr_accessor :profile, :identity, :build_path, :keychain
8
+ attr_accessor :profile, :identity, :build_path, :keychain, :sdk
7
9
 
8
10
  def initialize(config)
9
11
  if config.is_a? Xcode::Scheme
@@ -11,6 +13,7 @@ module Xcode
11
13
  config = config.launch
12
14
  end
13
15
  @target = config.target
16
+ @sdk = @target.project.sdk
14
17
  @config = config
15
18
  @build_path = "#{File.dirname(@target.project.path)}/build/"
16
19
  end
@@ -30,40 +33,33 @@ module Xcode
30
33
  p
31
34
  end
32
35
 
33
- def build
34
- profile = install_profile
35
-
36
- cmd = []
37
- cmd << "xcodebuild"
38
- cmd << "-sdk #{@target.project.sdk}" unless @target.project.sdk.nil?
39
- cmd << "-project \"#{@target.project.path}\""
40
-
41
- cmd << "-scheme #{@scheme.name}" unless @scheme.nil?
42
- cmd << "-target \"#{@target.name}\"" if @scheme.nil?
43
- cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
44
-
45
- cmd << "OTHER_CODE_SIGN_FLAGS=\"--keychain #{@keychain.path}\"" unless @keychain.nil?
46
- cmd << "CODE_SIGN_IDENTITY=\"#{@identity}\"" unless @identity.nil?
47
- cmd << "OBJROOT=\"#{@build_path}\""
48
- cmd << "SYMROOT=\"#{@build_path}\""
49
- cmd << "PROVISIONING_PROFILE=#{profile.uuid}" unless profile.nil?
50
- yield(cmd) if block_given?
51
-
36
+ def build(sdk=@sdk)
37
+ cmd = build_command(@sdk)
52
38
  Xcode::Shell.execute(cmd)
53
39
  end
54
40
 
55
41
  def test
56
- build do |cmd|
57
- cmd.select! do |line|
58
- !line=~/\^-sdk/
59
- end
60
-
61
- cmd << "TEST_AFTER_BUILD=YES"
62
- cmd << "TEST_HOST=''"
63
- cmd << "-sdk iphonesimulator5.0" # FIXME: hardcoded version, should be smarter
42
+ cmd = build_command('iphonesimulator')
43
+ cmd << "TEST_AFTER_BUILD=YES"
44
+ cmd << "TEST_HOST=''"
45
+
46
+ parser = Xcode::Test::ReportParser.new
47
+ Xcode::Shell.execute(cmd, false) do |line|
48
+ puts line
49
+ parser << line
64
50
  end
65
51
 
66
- Xcode::Shell.execute(cmd)
52
+ yield(parser) if block_given?
53
+
54
+ exit parser.exit_code if parser.exit_code!=0
55
+
56
+ parser
57
+ end
58
+
59
+ def upload(api_token, team_token)
60
+ testflight = Xcode::Testflight.new(api_token, team_token)
61
+ yield(testflight) if block_given?
62
+ testflight.upload(ipa_path, dsym_zip_path)
67
63
  end
68
64
 
69
65
  def clean
@@ -158,5 +154,27 @@ module Xcode
158
154
  "#{product_version_basename}.dSYM.zip"
159
155
  end
160
156
 
157
+
158
+ private
159
+
160
+ def build_command(sdk=@sdk)
161
+ profile = install_profile
162
+ cmd = []
163
+ cmd << "xcodebuild"
164
+ cmd << "-sdk #{sdk}" unless sdk.nil?
165
+ cmd << "-project \"#{@target.project.path}\""
166
+
167
+ cmd << "-scheme #{@scheme.name}" unless @scheme.nil?
168
+ cmd << "-target \"#{@target.name}\"" if @scheme.nil?
169
+ cmd << "-configuration \"#{@config.name}\"" if @scheme.nil?
170
+
171
+ cmd << "OTHER_CODE_SIGN_FLAGS=\"--keychain #{@keychain.path}\"" unless @keychain.nil?
172
+ cmd << "CODE_SIGN_IDENTITY=\"#{@identity}\"" unless @identity.nil?
173
+ cmd << "OBJROOT=\"#{@build_path}\""
174
+ cmd << "SYMROOT=\"#{@build_path}\""
175
+ cmd << "PROVISIONING_PROFILE=#{profile.uuid}" unless profile.nil?
176
+ cmd
177
+ end
178
+
161
179
  end
162
180
  end
@@ -37,7 +37,7 @@ module Xcode
37
37
  end
38
38
 
39
39
  def info_plist
40
- puts @json.inspect
40
+ # puts @json.inspect
41
41
  info = Xcode::InfoPlist.new(self, info_plist_location)
42
42
  yield info if block_given?
43
43
  info.save
data/lib/xcode/shell.rb CHANGED
@@ -8,6 +8,7 @@ module Xcode
8
8
  IO.popen (cmd) do |f|
9
9
  f.each do |line|
10
10
  puts line if show_output
11
+ yield(line) if block_given?
11
12
  out << line
12
13
  end
13
14
  end
@@ -0,0 +1,172 @@
1
+ require 'time'
2
+ require 'FileUtils'
3
+ require 'socket'
4
+ require 'builder'
5
+
6
+ module Xcode
7
+ module Test
8
+ module Formatters
9
+ class JunitFormatter
10
+ def initialize(dir)
11
+ @dir = dir
12
+ end
13
+
14
+ def string_to_xml(s)
15
+ s.gsub(/&/, '&amp;').gsub(/'/, '&quot;').gsub(/</, '&lt;')
16
+ end
17
+
18
+ def write(report)
19
+ if report.end_time.nil?
20
+ raise "Report #{report} #{report.name} has a nil end time!?"
21
+ end
22
+ xml = ::Builder::XmlMarkup.new( :indent => 2 )
23
+ xml.instruct! :xml, :encoding => "UTF-8"
24
+ xml.testsuite(:errors => report.total_error_tests,
25
+ :failures => report.total_failed_tests,
26
+ :hostname => Socket.gethostname,
27
+ :name => report.name,
28
+ :tests => report.tests.count,
29
+ :time => (report.end_time - report.start_time),
30
+ :timestamp => report.end_time
31
+ ) do |p|
32
+
33
+ report.tests.each do |t|
34
+ p.testcase(:classname => report.name,
35
+ :name => t.name,
36
+ :time => t.time
37
+ ) do |e|
38
+
39
+ if t.error?
40
+ e.failure t.error_location, :message => t.error_message, :type => 'Failure'
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ File.open("#{@dir}/TEST-#{report.name}.xml", 'w') do |current_file|
47
+ current_file.write xml.target!
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+
54
+ class SuiteReport
55
+ attr_accessor :tests, :name, :start_time, :end_time
56
+
57
+ def initialize(name, start_time)
58
+ @name = name
59
+ @start_time = start_time
60
+ @tests = []
61
+ end
62
+
63
+ def finish(time)
64
+ raise "Time is nil" if time.nil?
65
+ @end_time = time
66
+ end
67
+
68
+ def total_error_tests
69
+ @tests.select {|t| t.error? }.count
70
+ end
71
+
72
+ def total_passed_tests
73
+ @tests.select {|t| t.passed? }.count
74
+ end
75
+
76
+ def total_failed_tests
77
+ @tests.select {|t| t.failed? }.count
78
+ end
79
+
80
+ end
81
+
82
+ class CaseReport
83
+ attr_reader :name, :time, :error_message, :error_location
84
+
85
+ def initialize(name)
86
+ @name = name
87
+ end
88
+
89
+ def passed?
90
+ @passed
91
+ end
92
+
93
+ def failed?
94
+ error? or !@passed
95
+ end
96
+
97
+ def error?
98
+ !@error_message.nil?
99
+ end
100
+
101
+ def passed(time)
102
+ @passed = true
103
+ @time = time
104
+ end
105
+
106
+ def failed(time)
107
+ @passed = false
108
+ @time = time
109
+ end
110
+
111
+ def error(error_message,error_location)
112
+ @error_message = error_message
113
+ @error_location = error_location
114
+ end
115
+ end
116
+
117
+ class ReportParser
118
+
119
+ attr_reader :exit_code, :reports
120
+
121
+ def initialize
122
+ @exit_code = 0
123
+ @reports = []
124
+ end
125
+
126
+ def write(dir, format=:junit)
127
+ dir = File.expand_path(dir)
128
+ FileUtils.mkdir_p(dir)
129
+
130
+ formatter = Formatters.const_get("#{format.capitalize}Formatter").new(dir)
131
+ @reports.each do |r|
132
+ formatter.write(r)
133
+ end
134
+ end
135
+
136
+ def <<(piped_row)
137
+ case piped_row
138
+
139
+ when /Test Suite '(\S+)'.*started at\s+(.*)/
140
+ name = $1
141
+ time = Time.parse($2)
142
+ @reports << SuiteReport.new(name, time) unless name=~/\// # ignore if its a file path
143
+
144
+ when /Test Suite '(\S+)'.*finished at\s+(.*)./
145
+ @reports.last.finish(Time.parse($2))
146
+
147
+ when /Test Case '-\[\S+\s+(\S+)\]' started./
148
+ test = CaseReport.new($1)
149
+ @reports.last.tests << test
150
+
151
+ when /Test Case '-\[\S+\s+(\S+)\]' passed \((.*) seconds\)/
152
+ @reports.last.tests.last.passed($2.to_f)
153
+
154
+ when /(.*): error: -\[(\S+) (\S+)\] : (.*)/
155
+ @reports.last.tests.last.error(error_message,error_location)
156
+ @exit_code = 1 # should terminate
157
+
158
+ when /Test Case '-\[\S+ (\S+)\]' failed \((\S+) seconds\)/
159
+ @reports.last.tests.last.failed($2.to_f)
160
+ @exit_code = 1 # should terminate
161
+
162
+ when /failed with exit code (\d+)/
163
+ @exit_code = $1.to_i
164
+
165
+ when
166
+ /BUILD FAILED/
167
+ @exit_code = -1;
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,37 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ module Xcode
5
+ class Testflight
6
+ attr_accessor :api_token, :team_token, :notify, :proxy, :notes, :lists
7
+
8
+ def initialize(api_token, team_token)
9
+ @api_token = api_token
10
+ @team_token = team_token
11
+ @notify = true
12
+ @notes = nil
13
+ @lists = []
14
+ end
15
+
16
+ def upload(ipa_path, dsymzip_path=nil)
17
+ # cmd = []
18
+ RestClient.proxy = @proxy || ENV['http_proxy'] || ENV['HTTP_PROXY']
19
+ RestClient.log = '/tmp/restclient.log'
20
+
21
+ puts "Uploading to Testflight..."
22
+ response = RestClient.post('http://testflightapp.com/api/builds.json',
23
+ :file => File.new(ipa_path),
24
+ :dsym => File.new(dsymzip_path),
25
+ :api_token => @api_token,
26
+ :team_token => @team_token,
27
+ :notes => @notes,
28
+ :notify => @notify ? 'True' : 'False',
29
+ :distribution_lists => @lists.join(',')
30
+ )
31
+
32
+ json = JSON.parse(response)
33
+ puts " + Done, got: #{json.inspect}"
34
+ json
35
+ end
36
+ end
37
+ end
data/lib/xcode/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Xcode
2
- VERSION = "0.0.17"
2
+ VERSION = "0.0.18"
3
3
  end
@@ -0,0 +1,85 @@
1
+ require 'rspec'
2
+ require 'xcoder'
3
+
4
+ describe Xcode::Test::ReportParser do
5
+
6
+ def example_report
7
+ t = Xcode::Test::ReportParser.new
8
+ t << "Run test suite AnExampleTestSuite"
9
+ t << "Test Suite 'AnExampleTestSuite' started at 2012-02-10 00:37:04 +0000"
10
+
11
+ t << "Run test case anExampleTest1"
12
+ t << "Test Case '-[AnExampleTestSuite anExampleTest1]' started."
13
+ t << "Test Case '-[AnExampleTestSuite anExampleTest1]' passed (0.003 seconds)."
14
+
15
+ t << "Run test case anExampleTest2"
16
+ t << "Test Case '-[AnExampleTestSuite anExampleTest2]' started."
17
+ t << "Test Case '-[AnExampleTestSuite anExampleTest2]' passed (0.003 seconds)."
18
+
19
+ yield(t) if block_given?
20
+
21
+ t << "Test Suite 'AnExampleTestSuite' finished at 2012-02-10 00:37:04 +0000."
22
+ t << "Executed 1 test, with 0 failures (0 unexpected) in 0.000 (0.000) seconds"
23
+
24
+ t
25
+ end
26
+
27
+ def example_failing_report
28
+ example_report do |t|
29
+ t << "Test Case '-[AnExampleTestSuite aFailingTest]' started."
30
+ t << "Test Case '-[AnExampleTestSuite aFailingTest]' failed (2 seconds)."
31
+ end
32
+ end
33
+
34
+ it "should create a test case" do
35
+ t = example_report
36
+ t.reports.count.should==1
37
+ t.reports.first.name.should=="AnExampleTestSuite"
38
+ t.reports.first.start_time.should==Time.parse("2012-02-10 00:37:04 +0000")
39
+ t.reports.first.end_time.should==Time.parse("2012-02-10 00:37:04 +0000")
40
+ end
41
+
42
+ it "should set the exist status to 0" do
43
+ t = example_report
44
+ t.exit_code.should==0
45
+ end
46
+
47
+ it "should set the exit status to non 0" do
48
+ t = example_failing_report
49
+ t.exit_code.should_not==0
50
+ end
51
+
52
+ it "should record a failure" do
53
+ t = example_failing_report
54
+ t.reports.first.total_failed_tests.should==1
55
+ end
56
+
57
+ it "should create a test case with some tests" do
58
+ t = example_report
59
+
60
+ t.reports.count.should==1
61
+ t.reports.first.tests.count.should==2
62
+ t.reports.first.tests[0].name.should=='anExampleTest1'
63
+ t.reports.first.tests[0].time.should==0.003
64
+ t.reports.first.tests[0].passed?.should==true
65
+
66
+ t.reports.first.tests[1].name.should=='anExampleTest2'
67
+ t.reports.first.tests[1].time.should==0.003
68
+ t.reports.first.tests[1].passed?.should==true
69
+ end
70
+
71
+ it "should write out reports in junit format" do
72
+ report_dir = "#{File.dirname(__FILE__)}/test-reports"
73
+ FileUtils.rm_rf report_dir
74
+
75
+ t = example_report
76
+ t.write(report_dir, :junit)
77
+
78
+ files = Dir["#{report_dir}/*.xml"]
79
+ files.count.should==1
80
+ files.first.should=~/TEST-AnExampleTestSuite.xml$/
81
+
82
+ # FIXME: parse the report
83
+ end
84
+
85
+ end
data/xcoder.gemspec CHANGED
@@ -21,4 +21,6 @@ Gem::Specification.new do |s|
21
21
  s.add_runtime_dependency "json"
22
22
  s.add_runtime_dependency "plist"
23
23
  s.add_runtime_dependency "nokogiri"
24
+ s.add_runtime_dependency "builder"
25
+ s.add_runtime_dependency "rest-client"
24
26
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcoder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.17
4
+ version: 0.0.18
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-06 00:00:00.000000000Z
12
+ date: 2012-02-10 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: json
16
- requirement: &70168698844980 !ruby/object:Gem::Requirement
16
+ requirement: &70260058216360 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *70168698844980
24
+ version_requirements: *70260058216360
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: plist
27
- requirement: &70168698844560 !ruby/object:Gem::Requirement
27
+ requirement: &70260058215940 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *70168698844560
35
+ version_requirements: *70260058215940
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: nokogiri
38
- requirement: &70168698844140 !ruby/object:Gem::Requirement
38
+ requirement: &70260058215520 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,7 +43,29 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *70168698844140
46
+ version_requirements: *70260058215520
47
+ - !ruby/object:Gem::Dependency
48
+ name: builder
49
+ requirement: &70260058215100 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *70260058215100
58
+ - !ruby/object:Gem::Dependency
59
+ name: rest-client
60
+ requirement: &70260058214680 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *70260058214680
47
69
  description: Provides a ruby based object-model for parsing project structures and
48
70
  invoking builds
49
71
  email:
@@ -69,6 +91,8 @@ files:
69
91
  - lib/xcode/scheme.rb
70
92
  - lib/xcode/shell.rb
71
93
  - lib/xcode/target.rb
94
+ - lib/xcode/test/report_parser.rb
95
+ - lib/xcode/testflight.rb
72
96
  - lib/xcode/version.rb
73
97
  - lib/xcode/workspace.rb
74
98
  - lib/xcoder.rb
@@ -96,6 +120,7 @@ files:
96
120
  - spec/project_spec.rb
97
121
  - spec/scheme_spec.rb
98
122
  - spec/target_spec.rb
123
+ - spec/test_report_spec.rb
99
124
  - spec/workspace_spec.rb
100
125
  - xcoder.gemspec
101
126
  homepage: https://github.com/rayh/xcoder
@@ -147,4 +172,5 @@ test_files:
147
172
  - spec/project_spec.rb
148
173
  - spec/scheme_spec.rb
149
174
  - spec/target_spec.rb
175
+ - spec/test_report_spec.rb
150
176
  - spec/workspace_spec.rb