xcskarel 0.11.0 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cf58b04b0c57a70a57293e17fe3bb66bde17a5f8
4
- data.tar.gz: afb87c39726475e9e85b1c04d74bef54adb7a104
3
+ metadata.gz: f69158b3f6c2220edec0c74f13e59c1dc1785ae5
4
+ data.tar.gz: 2584d85e540450a8c65e52ea9f2987a23b93e8e3
5
5
  SHA512:
6
- metadata.gz: 8f8aaa7c01000090168ef4f12445395135508928271ae0db44bd9a8f57a7e9c13b7fcf6a3b633e4189948044ae25a60b559ebaef8785a3e0779d90d2a6709b39
7
- data.tar.gz: 9e0b9728393772d7ecef24d97162e31c10f023819fa3176fc7c9c16b7eb2b93b79ad12dee1e43630e0febbbbd5bbcfbd7477e38798e6b08c1413585f71beb7ed
6
+ metadata.gz: 2ecc1b825c615c8be675b732a52639553bcdbd34d10200499d70de79dd78bdf7ef82c70d794f5f7b2125cdd7a07d96e09b838de32a6e8e8551aa5cdf73e39833
7
+ data.tar.gz: 7136da6e5c5d838eb575d54aad6ffbcd060dce1265b0a87b76d9f4adba2e8b41354f306c7c544497c37237892381a1c6852770fb52bc3b1e98b3f8746d2e6b77
data/bin/xcskarel CHANGED
@@ -12,18 +12,25 @@ class XCSKarelApplication
12
12
  include Commander::Methods
13
13
 
14
14
  def add_xcs_options(c)
15
- c.option '--host Hostname', '(required) Xcode Server\'s hostname or IP address (default: localhost)'
16
- c.option '--user Username', 'Xcode Server username'
17
- c.option '--pass Password', 'Xcode Server password'
15
+ c.option '--host Hostname', 'Xcode Server\'s hostname or IP address (default: localhost) (also can be specified as the environment variable XCSKAREL_HOST)'
16
+ c.option '--user Username', 'Xcode Server username (also can be specified as the environment variable XCSKAREL_USER)'
17
+ c.option '--pass Password', 'Xcode Server password (also can be specified as the environment variable XCSKAREL_PASS)'
18
18
  end
19
19
 
20
20
  def add_bot_options(c)
21
- c.option '--bot BOT_ID', '(required) Bot identifier'
21
+ c.option '--bot BOT_ID_OR_NAME', '(required) Bot identifier or name'
22
+ end
23
+
24
+ def add_bot_or_integration_options(c)
25
+ c.option '--bot BOT_ID_OR_NAME', 'Bot identifier or name'
26
+ c.option '--integration INTEGRATION_ID', 'Integration identifier'
22
27
  end
23
28
 
24
29
  def create_server_from_options(options)
25
- host = options.host || "localhost"
26
- XCSKarel::Server.new(host, options.user, options.pass)
30
+ host = options.host || ENV['XCSKAREL_HOST'] || "localhost"
31
+ user = options.user || ENV['XCSKAREL_USER']
32
+ pass = options.pass || ENV['XCSKAREL_PASS']
33
+ XCSKarel::Server.new(host, user, pass)
27
34
  end
28
35
 
29
36
  def run
@@ -92,14 +99,7 @@ class XCSKarelApplication
92
99
  c.action do |args, options|
93
100
  server = create_server_from_options(options)
94
101
  all_bots = server.get_bots
95
- # create Bot instances
96
- # bot_objs = all_bots.map { |json| XCSKarel::Bot.new(json) }
97
- # bot_files = bot_objs.map { |bot| name = "./xcskarel/#{bot.json['_id']}.json"; bot.to_file(name); name }
98
- unless options.no_filter
99
- all_bots = XCSKarel::Filter.filter_key_paths(all_bots, ['name', '_id'])
100
- end
101
- out = options.no_pretty ? JSON.generate(all_bots) : JSON.pretty_generate(all_bots)
102
- puts out
102
+ puts XCSKarel::Application.format(all_bots, options, ['name', '_id'])
103
103
  end
104
104
  end
105
105
 
@@ -112,12 +112,37 @@ class XCSKarelApplication
112
112
  c.action do |args, options|
113
113
  raise "No Bot id was specified, please see `xcskarel integrations --help`" unless options.bot
114
114
  server = create_server_from_options(options)
115
- all_integrations = server.get_integrations(options.bot)
116
- unless options.no_filter
117
- all_integrations = XCSKarel::Filter.filter_key_paths(all_integrations, ['number', '_id', 'currentStep', 'result'])
118
- end
119
- out = options.no_pretty ? JSON.generate(all_integrations) : JSON.pretty_generate(all_integrations)
120
- puts out
115
+ all_integrations = XCSKarel::Application.integrations(server, options.bot)
116
+ puts XCSKarel::Application.format(all_integrations, options, ['number', '_id', 'currentStep', 'result'])
117
+ end
118
+ end
119
+
120
+ command :issues do |c|
121
+ c.syntax = 'xcskarel issues [options]'
122
+ c.description = 'Fetches issues of an integration or a Bot\'s last integration'
123
+ c.example 'fetches issues for a given integration on localhost', 'xcskarel issues --integration 448946985304230369392c2e6b05a821'
124
+ c.example 'fetches issues for a given bot\'s last integration', 'xcskarel issues --bot "My Bot" --host 192.168.1.64'
125
+ add_xcs_options(c)
126
+ add_bot_or_integration_options(c)
127
+ c.action do |args, options|
128
+ server = create_server_from_options(options)
129
+ bot = options.bot
130
+ integration = options.integration
131
+ raise "Exactly one of Bot or Integration must be specified, please see `xcskarel issues --help`" unless bot || integration
132
+ all_issues = XCSKarel::Application.issues(server, bot, integration)
133
+ key_paths = [
134
+ 'buildServiceErrors.*',
135
+ 'buildServiceWarnings.message',
136
+ 'triggerErrors.*',
137
+ 'analyzerWarnings.*',
138
+ 'errors.*.message',
139
+ 'testFailures.*.testCase',
140
+ 'testFailures.*.documentFilePath',
141
+ 'testFailures.*.message',
142
+ 'warnings.*.message',
143
+ 'warnings.*.documentFilePath'
144
+ ]
145
+ puts XCSKarel::Application.format(all_issues, options, key_paths, false)
121
146
  end
122
147
  end
123
148
 
@@ -144,11 +169,7 @@ class XCSKarelApplication
144
169
  c.action do |args, options|
145
170
  server = create_server_from_options(options)
146
171
  all_health = server.get_health
147
- unless options.no_filter
148
- all_health = XCSKarel::Filter.filter_key_paths(all_health, ['uptime'])
149
- end
150
- out = options.no_pretty ? JSON.generate(all_health) : JSON.pretty_generate(all_health)
151
- puts out
172
+ puts XCSKarel::Application.format(all_health, options, ['uptime'])
152
173
  end
153
174
  end
154
175
 
@@ -1,3 +1,6 @@
1
+ require 'xcskarel/filter'
2
+ require 'json'
3
+
1
4
  module XCSKarel
2
5
  module Application
3
6
  def self.choose_bot(server)
@@ -91,6 +94,12 @@ module XCSKarel
91
94
  puts table.to_s
92
95
  end
93
96
 
97
+ def self.integrations(server, bot_id_or_name)
98
+ bot = server.find_bot_by_id_or_name(bot_id_or_name)
99
+ XCSKarel.log.debug "Found Bot #{bot['name']} with id #{bot['_id']}".yellow
100
+ server.get_integrations(bot['_id'])
101
+ end
102
+
94
103
  def self.integrate(server, bot_id_or_name)
95
104
 
96
105
  # find bot by id or name
@@ -104,5 +113,50 @@ module XCSKarel
104
113
  self.print_status(server)
105
114
  end
106
115
 
116
+ def self.issues(server, bot_id_or_name, integration_id)
117
+ integration = nil
118
+ if bot_id_or_name
119
+ bot = server.find_bot_by_id_or_name(bot_id_or_name)
120
+ # fetch last integration
121
+ integration = (server.get_integrations(bot['_id']).first || {})['_id']
122
+ raise "No Integration found for Bot \"#{bot['name']}\"".red unless integration
123
+ else
124
+ integration = server.get_integration(integration_id)['_id']
125
+ raise "No Integration found for id #{integration_id}".red unless integration
126
+ end
127
+
128
+ # fetch issues
129
+ issues = server.get_issues(integration)
130
+ return issues
131
+ end
132
+
133
+ def self.format(object, options, allowed_key_paths, allow_empty_container_leaves=true)
134
+ unless options.no_filter
135
+
136
+ extra_filters = []
137
+
138
+ unless allow_empty_container_leaves
139
+ # optionally add an override to filter out empty containers as leaves
140
+ empty_leaves = lambda do |k,v|
141
+ return true unless v.is_a?(Array) || v.is_a?(Hash)
142
+ return v.count > 0
143
+ end
144
+ extra_filters << empty_leaves
145
+ end
146
+
147
+ # create a super-filter composed from all the gathered filters
148
+ custom_filters = lambda do |k,v|
149
+ extra_filters.each do |filter|
150
+ return false unless filter.call(k,v)
151
+ end
152
+ return true
153
+ end
154
+
155
+ object = XCSKarel::Filter.filter_key_paths(object, allowed_key_paths, custom_filters)
156
+ end
157
+ out = options.no_pretty ? JSON.generate(object) : JSON.pretty_generate(object)
158
+ return out
159
+ end
160
+
107
161
  end
108
162
  end
@@ -6,11 +6,11 @@ module XCSKarel
6
6
  # returns a copy of the passed-in hash with only the provided keypaths kept
7
7
  # e.g. "name" will keep the key "name" at the top level.
8
8
  # supports even nested keypaths
9
- def self.filter_key_paths(object, key_paths)
9
+ def self.filter_key_paths(object, key_paths, custom_block=nil)
10
10
 
11
11
  # array?
12
12
  if object.is_a?(Array)
13
- return self.filter_array(object, key_paths)
13
+ return self.filter_array(object, key_paths, custom_block)
14
14
  end
15
15
 
16
16
  # hash?
@@ -19,14 +19,31 @@ module XCSKarel
19
19
  unique_key_paths = Set.new(key_paths)
20
20
  object.each do |k,v|
21
21
 
22
+ next if !custom_block.nil? && !custom_block.call(k, v)
23
+
22
24
  keys = k.split('.') # key-paths must be separated by a period
23
- match = unique_key_paths.select do |key|
24
- key.split('.').first == keys.first
25
- end.first
26
- if match
27
- child_key_paths = match.split('.').drop(1)
25
+ matches = unique_key_paths.select do |key|
26
+ kp = key.split('.')
27
+ kp.first == keys.first || kp.first == "*"
28
+ end
29
+ if matches.count > 0
30
+
31
+ child_key_paths = []
32
+ split_matches = matches.map { |match| match.split('.') }
33
+
34
+ # universal wildcard
35
+ if matches.index("*") != nil
36
+ child_key_paths = child_key_paths << "*"
37
+ else
38
+ # normal key-path (including key-pathed wildcard)
39
+ child_key_paths = child_key_paths + split_matches.map { |split_match| split_match.drop(1).join('.') }
40
+ end
41
+
28
42
  # if there are no more key paths, we just take everything (whitelisted by default)
29
- new_hash[keys.first] = child_key_paths.count == 0 ? v : filter_key_paths(v, child_key_paths)
43
+ new_k = keys.first
44
+ new_v = filter_key_paths(v, child_key_paths, custom_block)
45
+ next if !custom_block.nil? && !custom_block.call(new_k, new_v)
46
+ new_hash[new_k] = new_v
30
47
  end
31
48
  end
32
49
  return new_hash
@@ -39,11 +56,11 @@ module XCSKarel
39
56
  private
40
57
 
41
58
  # filters each element
42
- def self.filter_array(array, key_paths)
59
+ def self.filter_array(array, key_paths, custom_block=nil)
43
60
  new_array = Array.new
44
61
  keys = Set.new(key_paths)
45
62
  array.each do |i|
46
- new_array << filter_key_paths(i, key_paths)
63
+ new_array << filter_key_paths(i, key_paths, custom_block)
47
64
  end
48
65
  return new_array
49
66
  end
@@ -31,12 +31,29 @@ module XCSKarel
31
31
  bots.sort_by { |bot| bot['name'] }
32
32
  end
33
33
 
34
- def get_integrations(bot_id)
35
- response = get_endpoint("/bots/#{bot_id}/integrations")
34
+ def get_integrations(bot_id, limit=nil)
35
+ raise "No Bot id provided".red if !bot_id || bot_id.empty?
36
+ limit_s = limit ? "?last=#{limit}" : ""
37
+ response = get_endpoint("/bots/#{bot_id}/integrations#{limit_s}")
36
38
  raise "Failed to fetch Integrations for Bot #{bot_id} from Xcode Server at #{@host}, response: #{response.status}: #{response.body}".red if response.status != 200
37
39
  JSON.parse(response.body)['results']
38
40
  end
39
41
 
42
+ def get_integration(integration_id)
43
+ raise "No Integration id provided".red if !integration_id || integration_id.empty?
44
+ response = get_endpoint("/integrations/#{integration_id}")
45
+ raise "Failed to fetch an Integrations with id #{integration_id} from Xcode Server at #{@host}, response: #{response.status}: #{response.body}".red if response.status != 200
46
+ JSON.parse(response.body)
47
+ end
48
+
49
+ def get_issues(integration_id)
50
+ raise "No Integration id provided".red if !integration_id || integration_id.empty?
51
+ response = get_endpoint("/integrations/#{integration_id}/issues")
52
+ raise "Failed to fetch issues for an Integrations with id #{integration_id} from Xcode Server at #{@host}, response: #{response.status}: #{response.body}".red if response.status != 200
53
+ body = JSON.parse(response.body)
54
+ return body['results'] || body # support both xcode 6 and 7
55
+ end
56
+
40
57
  def get_health
41
58
  response = get_endpoint("/health")
42
59
  raise "Failed to get Health of #{@host}" if response.status != 200
@@ -52,7 +69,7 @@ module XCSKarel
52
69
  status['name'] = bot['name']
53
70
  status['id'] = bot['_id']
54
71
  status['branch'] = XCSKarel::Config.new(bot, nil, nil).branch
55
- last_integration = self.get_integrations(bot['_id']).first # sorted from newest to oldest
72
+ last_integration = self.get_integrations(bot['_id'], 1).first # sorted from newest to oldest
56
73
  if last_integration
57
74
  status['current_step'] = last_integration['currentStep']
58
75
  status['result'] = last_integration['result']
@@ -78,10 +95,10 @@ module XCSKarel
78
95
  return integration
79
96
  end
80
97
 
81
- def find_bot_by_id_or_name(id_or_name)
98
+ def find_bot_by_id_or_name(id_or_name, raise_if_none_found=true)
82
99
  bots = self.get_bots
83
100
  found_bots = bots.select { |bot| [bot['name'], bot['_id']].index(id_or_name) != nil }
84
- raise "No Bot found for \"#{id_or_name}\"".red if found_bots.count == 0
101
+ raise "No Bot found for \"#{id_or_name}\"".red if raise_if_none_found && found_bots.count == 0
85
102
  XCSKarel.log.warn "More than one Bot found for \"#{id_or_name}\", taking the first one (you shouldn't have more Bots with the same name!)".red if found_bots.count > 1
86
103
  return found_bots.first
87
104
  end
@@ -1,3 +1,3 @@
1
1
  module XCSKarel
2
- VERSION = '0.11.0'
2
+ VERSION = '0.14.0'
3
3
  end
@@ -0,0 +1,39 @@
1
+ require 'xcskarel/application'
2
+
3
+ class Opts
4
+ attr_accessor :no_pretty
5
+ attr_accessor :no_filter
6
+ end
7
+
8
+ describe XCSKarel do
9
+ describe XCSKarel::Application do
10
+ describe "format" do
11
+
12
+ def default_options
13
+ opts = Opts.new
14
+ opts.no_filter = false
15
+ opts.no_pretty = false
16
+ return opts
17
+ end
18
+
19
+ it "filters correctly empty leaf arrays" do
20
+ object = [{
21
+ "errors" => {
22
+ "unresolvedIssues" => [],
23
+ "resolvedIssues" => []
24
+ },
25
+ "testFailures" => {
26
+ "unresolvedIssues" => ["one"],
27
+ "resolvedIssues" => []
28
+ }
29
+ }]
30
+ exp = JSON.pretty_generate([{
31
+ "testFailures" => {
32
+ "unresolvedIssues" => ["one"]
33
+ }
34
+ }])
35
+ expect(XCSKarel::Application.format(object, default_options, ["errors.*", "testFailures.*"], false)).to eq(exp)
36
+ end
37
+ end
38
+ end
39
+ end
data/spec/filter_spec.rb CHANGED
@@ -3,8 +3,8 @@ require 'xcskarel/filter'
3
3
  describe XCSKarel do
4
4
  describe XCSKarel::Filter do
5
5
 
6
- def test(inObj, key_paths)
7
- XCSKarel::Filter.filter_key_paths(inObj, key_paths)
6
+ def test(inObj, key_paths, custom_block=nil)
7
+ XCSKarel::Filter.filter_key_paths(inObj, key_paths, custom_block)
8
8
  end
9
9
 
10
10
  it "handles empty hash" do
@@ -59,7 +59,7 @@ describe XCSKarel do
59
59
  "old" => -2
60
60
  }
61
61
  }
62
- expect(test(obj, ["oranges", "apples"])).to eq(exp)
62
+ expect(test(obj, ["oranges.*", "apples"])).to eq(exp)
63
63
  end
64
64
 
65
65
  it "handles basic key path with an array without popping the key path" do
@@ -78,5 +78,48 @@ describe XCSKarel do
78
78
  ]
79
79
  expect(test(obj, ["new"])).to eq(exp)
80
80
  end
81
+
82
+ it "custom block can override and filter out based on keys" do
83
+ obj = [
84
+ "apples",
85
+ {
86
+ "new" => ["one", "two"],
87
+ "old" => []
88
+ }
89
+ ]
90
+ exp = [
91
+ "apples",
92
+ {
93
+ "new" => ["one", "two"]
94
+ }
95
+ ]
96
+ custom_block = lambda do |k,v|
97
+ return true unless v.is_a?(Array)
98
+ return v.count > 0
99
+ end
100
+ expect(test(obj, ["new", "old"], custom_block)).to eq(exp)
101
+ end
102
+
103
+ it "handles the wildcard symbol in the middle of a keypath" do
104
+ obj = {
105
+ "errors" => {
106
+ "status" => 0,
107
+ "data" => "1234abcd"
108
+ },
109
+ "warnings" => {
110
+ "status" => 1,
111
+ "data" => "abcd1234"
112
+ }
113
+ }
114
+ exp = {
115
+ "errors" => {
116
+ "status" => 0
117
+ },
118
+ "warnings" => {
119
+ "status" => 1
120
+ }
121
+ }
122
+ expect(test(obj, ["*.status"])).to eq(exp)
123
+ end
81
124
  end
82
125
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xcskarel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Honza Dvorsky
@@ -196,6 +196,7 @@ files:
196
196
  - lib/xcskarel/server.rb
197
197
  - lib/xcskarel/version.rb
198
198
  - lib/xcskarel/xcsfile.rb
199
+ - spec/application_spec.rb
199
200
  - spec/default_spec.rb
200
201
  - spec/filter_spec.rb
201
202
  homepage: http://github.com/czechboy0/xcskarel
@@ -223,6 +224,7 @@ signing_key:
223
224
  specification_version: 4
224
225
  summary: Manage your Xcode Server & Bots from the command line
225
226
  test_files:
227
+ - spec/application_spec.rb
226
228
  - spec/default_spec.rb
227
229
  - spec/filter_spec.rb
228
230
  has_rdoc: