roku_builder 4.28.0 → 4.29.2

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
  SHA256:
3
- metadata.gz: 46e81906787a2404d186ec7a628e03c41a9b918c0f9af442c3bfd49e765df12b
4
- data.tar.gz: befa6a6ba8d8f4ccac02080ac26644b010366cfbeefe3e13e278abadff48a75c
3
+ metadata.gz: f65c1d45145a53ba384191e6ca28de7698ce3f38300133293ae9d1639945ee8f
4
+ data.tar.gz: 556b118faaa21814e4c8bf7c3d68c94a1a6360e029ce3bc2351d1f7a24fb5563
5
5
  SHA512:
6
- metadata.gz: 2d332bb657dcbb40691b521e8c65f8dca2357ad7fb53e94af334c1e5c9e8acabe4e0dc4eaa5f3bc40fd13e1190d2a2ac201dd9cb61c6258baf8bbbb88592f9a1
7
- data.tar.gz: d0ab2b92f24d46a305ee943635e75e2513240679db8316b71591b3dc97e525689155e79acf7fe8560fdd2777b0887330f0f4f4c94ecb379bafa2ccfcf060daa4
6
+ metadata.gz: ab7e70ba97918b750a18ea9774ad2bb871d0e5162d1f006d8ab7a20f2981fe212ac48bc89a66bac2a666ee744c73720e7b51c52f2f3136ff6e72193d6e880313
7
+ data.tar.gz: ddb429ba2119e3a26e8bc775dbd7092c8d37f0d6ee38567f5fe2875cae2a1a12a32d4c8a5cae5b79cb678fe8c908f5422d15cab5b9cd14aa96804ac519ffbfc3
@@ -127,7 +127,6 @@ module RokuBuilder
127
127
  if File.exist?(local_config_path) and !@loaded_configs.include?(File.expand_path(local_config_path))
128
128
  local_config_hash = read_config(File.open(local_config_path))
129
129
  add_missing_directories(local_config_hash)
130
- local_sub_configs = "./.roku_config/*.json"
131
130
  @config = @config.deep_merge(local_config_hash)
132
131
  Dir.glob("./.roku_config/*.json").each do |sub_config_path|
133
132
  sub_config_hash = read_config(File.open(sub_config_path))
@@ -22,6 +22,7 @@ module RokuBuilder
22
22
  def parse_config
23
23
  process_in_argument
24
24
  setup_devices
25
+ setup_api_keys
25
26
  setup_project
26
27
  setup_in_out_file
27
28
  setup_project_config
@@ -41,6 +42,10 @@ module RokuBuilder
41
42
  @parsed[:devices] = @config[:devices].select{|key, value| :default != key}
42
43
  end
43
44
 
45
+ def setup_api_keys
46
+ @parsed[:api_keys] = @config[:api_keys]
47
+ end
48
+
44
49
  def setup_project
45
50
  if project_required and not @options[:project]
46
51
  project = current_project
@@ -26,7 +26,7 @@ module RokuBuilder
26
26
  KEY_MISSING_PATH = 19
27
27
  KEY_MISSING_PASSWORD = 20
28
28
  INVALID_MAPPING_INFO = 21
29
- # = 22
29
+ INVALID_API_KEY = 22
30
30
  MISSING_STAGE_METHOD = 23
31
31
 
32
32
  def initialize(config:)
@@ -63,7 +63,7 @@ module RokuBuilder
63
63
  def validate_config
64
64
  @codes = []
65
65
  validate_structure
66
- [:projects, :devices, :keys, :input_mappings].each do |section|
66
+ [:projects, :devices, :keys, :input_mappings, :api_keys].each do |section|
67
67
  validate_section(section: section) if @config[section]
68
68
  end
69
69
  @codes.uniq!
@@ -174,6 +174,13 @@ module RokuBuilder
174
174
  process_errors(errors: errors)
175
175
  end
176
176
 
177
+ def validate_api_key(api_key:)
178
+ errors = [
179
+ [INVALID_API_KEY, (api_key.class != String)]
180
+ ]
181
+ process_errors(errors: errors)
182
+ end
183
+
177
184
  def process_errors(errors:)
178
185
  errors.each do |error|
179
186
  @codes.push(error[0]) if error[1]
@@ -115,7 +115,7 @@ module RokuBuilder
115
115
  multipart_connection(device: device) do |conn|
116
116
  response = conn.post "/plugin_install", payload
117
117
  end
118
- unless response.status == 200 and response.body =~ /squashfs file in internal memory/ or ignoreFailure
118
+ unless response.status == 200 and response.body =~ /Conversion succeeded/ or ignoreFailure
119
119
  raise ExecutionError, "Failed Converting to Squashfs"
120
120
  end
121
121
  end
@@ -135,7 +135,7 @@ module RokuBuilder
135
135
  # @param txt [String] current string from telnet
136
136
  # @param regexp [Regexp] regular expression to filter text on
137
137
  # @return [String] remaining partial line text
138
- def manage_text(all_text:, txt:, regexp: nil, logging: false, logfile:)
138
+ def manage_text(all_text:, txt:, regexp: nil, logging: false, logfile: nil)
139
139
  raise ExecutionError, "Connection Closed" unless txt
140
140
  if /connection is already in use/ =~ txt
141
141
  raise ExecutionError, "Connection is in use"
@@ -82,7 +82,7 @@ module RokuBuilder
82
82
  get_device(device: device) do |device|
83
83
  oldId = dev_id(device: device)
84
84
 
85
- raise ExecutionError, "Missing Key Config" unless @config.key
85
+ raise ExecutionError, "No Key Found For Stage #{options[:stage]}" unless @config.key
86
86
 
87
87
  # upload new key with password
88
88
  payload = {
@@ -0,0 +1,181 @@
1
+ # ********** Copyright Viacom, Inc. Apache 2.0 **********
2
+
3
+ module RokuBuilder
4
+
5
+ # Load/Unload/Build roku applications
6
+ class RokuAPI < Util
7
+ extend Plugin
8
+
9
+ HOST = "https://apipub.roku.com"
10
+
11
+ def init
12
+ end
13
+
14
+ def self.commands
15
+ {
16
+ submit: {source: false},
17
+ publish: {}
18
+ }
19
+ end
20
+
21
+ def self.parse_options(parser:, options:)
22
+ parser.separator "Commands:"
23
+ parser.on("--submit", 'Submit a package to the Roku Portal') do
24
+ options[:submit] = true
25
+ end
26
+ parser.on("--publish", 'Publish an app on the Roku Portal') do
27
+ options[:publish] = true
28
+ end
29
+ parser.separator "Options:"
30
+ parser.on("--channel-id ID", 'ID of the channel to submit to/publish') do |id|
31
+ options[:channel_id] = id
32
+ end
33
+ parser.on("--api-key KEY", 'The API key to use to submit/publish') do |key|
34
+ options[:api_key] = key
35
+ end
36
+ parser.on("--no-publish", 'Prevent the channel from being automatically published when submitted') do
37
+ options[:no_publish] = true
38
+ end
39
+ end
40
+
41
+ def self.dependencies
42
+ []
43
+ end
44
+
45
+ def submit(options:)
46
+ raise RokuBuilder::InvalidOptions, "Missing channel id" unless options[:channel_id]
47
+ @logger.info "Submit to channel #{options[:channel_id]}"
48
+ @api_key = options[:api_key]
49
+ @no_publish = !!options[:no_publish]
50
+ response = get_channel_versions(options[:channel_id])
51
+ if response.first["channelState"] == "Unpublished"
52
+ response = update_channel_version(options[:channel_id], get_package(options), response.last["id"])
53
+ else
54
+ response = create_channel_version(options[:channel_id], get_package(options))
55
+ end
56
+ raise RokuBuilder::ExecutionError, "Request failed: #{response.reason_phrase}" unless response.success?
57
+ JSON.parse(response.body)
58
+ end
59
+
60
+ def publish(options:)
61
+ raise RokuBuilder::InvalidOptions, "Missing channel id" unless options[:channel_id]
62
+ @logger.info "Publish to channel #{options[:channel_id]}"
63
+ @api_key = options[:api_key]
64
+ response = get_channel_versions(options[:channel_id])
65
+ raise RokuBuilder::ExecutionError unless response.first["channelState"] == "Unpublished"
66
+ response = publish_channel_version(options[:channel_id], response.first["id"])
67
+ raise RokuBuilder::ExecutionError, "Request failed: #{response.reason_phrase}" unless response.success?
68
+ JSON.parse(response.body)
69
+ end
70
+
71
+ private
72
+
73
+ def get_package(options)
74
+ File.open(options[:in])
75
+ end
76
+
77
+ def api_path
78
+ "/developer/v1"
79
+ end
80
+
81
+ def get_channel_versions(channel)
82
+ path = "/external/channels/#{channel}/versions"
83
+ response = api_get(path)
84
+ sorted_versions(JSON.parse(response.body))
85
+ end
86
+
87
+ def sorted_versions(versions)
88
+ sorted = versions.sort do |a, b|
89
+ DateTime.parse(b["createdDate"]) <=> DateTime.parse(a["createdDate"])
90
+ end
91
+ sorted
92
+ end
93
+
94
+ def create_channel_version(channel, package)
95
+ path = "/external/channels/#{channel}/versions"
96
+ params = nil
97
+ unless @no_publish
98
+ params = {"channelState" => "Published"}
99
+ end
100
+ api_post(path, path, package, params)
101
+ end
102
+
103
+ def update_channel_version(channel, package, version)
104
+ path = "/external/channel/#{channel}/#{version}"
105
+ token_path = "/external/channels/#{channel}/#{version}"
106
+ api_patch(path, token_path, package)
107
+ end
108
+
109
+ def publish_channel_version(channel, version)
110
+ path = "/external/channels/#{channel}/versions/#{version}"
111
+ token_path = "/external/channels/#{channel}/versions/#{version}/state"
112
+ api_post(path, token_path)
113
+ end
114
+
115
+ def api_get(path)
116
+ service_urn = "urn:roku:cloud-services:chanprovsvc"
117
+ connection('GET', path, nil).get(api_path+path)
118
+ end
119
+
120
+ def api_post(path, token_path, package=nil, params = nil)
121
+ body = {}.to_json
122
+ if package
123
+ body = {
124
+ "appFileBase64Encoded" => Base64.encode64(package.read)
125
+ }.to_json
126
+ end
127
+ connection('POST', token_path, body).post(api_path+path) do |request|
128
+ if params
129
+ request.params = params
130
+ end if
131
+ request.body = body
132
+ end
133
+ end
134
+
135
+ def api_patch(path, token_path, package)
136
+ body = {
137
+ "path" => "/appFileBase64Encoded",
138
+ "value" => Base64.encode64(package.read),
139
+ "op" => "replace"
140
+ }.to_json
141
+ response = connection('PATCH', token_path, body).patch(api_path+path) do |request|
142
+ request.body = body
143
+ end
144
+ end
145
+
146
+ def connection(method, path, body)
147
+ service_urn = "urn:roku:cloud-services:chanprovsvc"
148
+ connection = Faraday.new(url: HOST, headers: {
149
+ 'Authorization' => "Bearer "+get_jwt_token(@api_key, service_urn, method, path, body),
150
+ 'Content-Type' => 'application/json',
151
+ 'Accept' => 'application/json',
152
+ }) do |f|
153
+ f.adapter Faraday.default_adapter
154
+ end
155
+ end
156
+
157
+ def get_jwt_token(api_key, service_urn, method, path, body = nil)
158
+ key_file = File.expand_path(@config.api_keys[api_key.to_sym])
159
+ raise InvalidOptions "Missing api key" unless key_file
160
+ jwk = JWT::JWK.new(JSON.parse(File.read(key_file)))
161
+ header = {
162
+ "typ" => "JWT",
163
+ "kid" => jwk.export[:kid]
164
+ }
165
+ payload = {
166
+ "exp" => (Time.now + (12*60*60)).to_i,
167
+ "x-roku-request-key" => SecureRandom.uuid,
168
+ "x-roku-request-spec" => {
169
+ "serviceUrn" => service_urn,
170
+ "httpMethod" => method,
171
+ "path" => path,
172
+ }
173
+ }
174
+ if body
175
+ payload["x-roku-request-spec"]["bodySha256Base64"] = Digest::SHA256.base64digest(body)
176
+ end
177
+ JWT.encode(payload, jwk.signing_key, 'RS256', header)
178
+ end
179
+ end
180
+ RokuBuilder.register_plugin(RokuAPI)
181
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module RokuBuilder
4
4
  # Version of the RokuBuilder Gem
5
- VERSION = "4.28.0"
5
+ VERSION = "4.29.2"
6
6
  end
data/lib/roku_builder.rb CHANGED
@@ -27,6 +27,9 @@ require "tmpdir"
27
27
  require "zip"
28
28
  #analyzer
29
29
  require "image_size"
30
+ #rokuapi
31
+ require "jwt"
32
+ require "base64"
30
33
 
31
34
 
32
35
  Dir.glob(File.join(File.dirname(__FILE__), "roku_builder", "*.rb")).each do |path|
data/roku_builder.gemspec CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.add_dependency "nokogiri", "~> 1.12"
31
31
  spec.add_dependency "win32-security", "~> 0.5" # For windows compatibility
32
32
  spec.add_dependency "image_size", "~> 2.0"
33
+ spec.add_dependency "jwt", "~> 2.7"
33
34
 
34
35
  spec.add_development_dependency "bundler", "~> 2.0"
35
36
  spec.add_development_dependency "rake", "~> 12.0"
@@ -153,11 +153,10 @@ module RokuBuilder
153
153
  logger.expect(severity, nil, [String])
154
154
 
155
155
  ::Logger.stub :new, logger do
156
- warnings = test_file(text: text, quiet: false)
156
+ test_file(text: text, quiet: false)
157
157
  end
158
158
 
159
159
  logger.verify
160
- warnings
161
160
  end
162
161
 
163
162
  def test(quiet=true)
@@ -120,8 +120,6 @@ module RokuBuilder
120
120
  assert help_text
121
121
  end
122
122
  def test_core_get_plugin_by_name
123
- parser = OptionParser.new
124
- options = {}
125
123
  plugin_name = Core.get_plugin_by_name("core")
126
124
  refute_nil plugin_name
127
125
  assert_match "RokuBuilder::Core", plugin_name.to_s
@@ -136,7 +136,7 @@ module RokuBuilder
136
136
  end
137
137
  def test_loader_squash
138
138
  @request_stubs.push(stub_request(:post, "http://#{@device_config[:ip]}/plugin_install").
139
- to_return(status: 200, body: "squashfs file in internal memory", headers: {}))
139
+ to_return(status: 200, body: "Conversion succeeded", headers: {}))
140
140
  @device_manager.expect(:reserve_device, @device, no_lock: false)
141
141
  @device_manager.expect(:release_device, nil, [@device])
142
142
 
@@ -0,0 +1,566 @@
1
+ # ********** Copyright Viacom, Inc. Apache 2.0 **********
2
+
3
+ require_relative "../test_helper.rb"
4
+
5
+ module RokuBuilder
6
+ class RokuAPITest < Minitest::Test
7
+ def setup
8
+ Logger.set_testing
9
+ RokuBuilder.class_variable_set(:@@dev, false)
10
+ RokuBuilder.setup_plugins
11
+ register_plugins(RokuAPI)
12
+ @config, @options = build_config_options_objects(RokuAPITest, {submit: true, channel_id: "1234", api_key: "key1"}, false)
13
+ @requests = []
14
+ end
15
+
16
+ def teardown
17
+ @requests.each {|req| remove_request_stub(req)}
18
+ WebMock.reset!
19
+ end
20
+
21
+ def test_commands
22
+ commands = RokuAPI.commands
23
+ refute_nil commands[:submit]
24
+ refute_nil commands[:publish]
25
+ end
26
+
27
+ def test_parse_options
28
+ parser = OptionParser.new
29
+ options = {}
30
+ RokuAPI.parse_options(parser: parser, options: options)
31
+ argv = ["roku", "--submit", "--publish", "--channel-id", "1234", "--api-key", "key1", "--no-publish"]
32
+ parser.parse! argv
33
+ assert options[:submit]
34
+ assert options[:publish]
35
+ assert_equal options[:channel_id], "1234"
36
+ assert_equal options[:api_key], "key1"
37
+ assert options[:no_publish]
38
+ end
39
+
40
+ def test_dependencies
41
+ assert_kind_of Array, RokuAPI.dependencies
42
+ assert_equal RokuAPI.dependencies.count, 0
43
+ end
44
+
45
+ def test_get_package
46
+ api = RokuAPI.new(config: @config)
47
+ options = {in: "in/path"}
48
+ called = false
49
+ open_proc = proc do |path|
50
+ called = true
51
+ assert_equal options[:in], path
52
+ end
53
+ File.stub(:open, open_proc) do
54
+ api.send(:get_package, options)
55
+ end
56
+ assert called
57
+ end
58
+
59
+ def test_api_path
60
+ api = RokuAPI.new(config: @config)
61
+ assert_equal "/developer/v1", api.send(:api_path)
62
+ end
63
+
64
+ def test_sorted_versions
65
+ api = RokuAPI.new(config: @config)
66
+ versions = [
67
+ {"version" => "1.9", "createdDate" => (DateTime.now - 30).to_s},
68
+ {"version" => "1.11", "createdDate" => (DateTime.now - 20).to_s},
69
+ {"version" => "2.3", "createdDate" => (DateTime.now - 10).to_s},
70
+ {"version" => "2.4", "createdDate" => (DateTime.now).to_s}
71
+ ]
72
+ sorted = api.send(:sorted_versions, versions)
73
+ assert_equal "2.4", sorted[0]["version"]
74
+ assert_equal "2.3", sorted[1]["version"]
75
+ assert_equal "1.11", sorted[2]["version"]
76
+ assert_equal "1.9", sorted[3]["version"]
77
+ versions = [
78
+ {"version" => "1.4", "createdDate" => (DateTime.now).to_s},
79
+ {"version" => "1.3", "createdDate" => (DateTime.now - 10).to_s}
80
+ ]
81
+ sorted = api.send(:sorted_versions, versions)
82
+ assert_equal "1.4", sorted[0]["version"]
83
+ assert_equal "1.3", sorted[1]["version"]
84
+ end
85
+
86
+ def test_get_jwt_token
87
+ api = RokuAPI.new(config: @config)
88
+ urn = "test:urn"
89
+ method = "GET"
90
+ path = "/test/path"
91
+ token = api.send(:get_jwt_token, @options[:api_key], urn, method, path)
92
+ jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
93
+ decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
94
+ assert_equal decoded[1]["typ"], "JWT"
95
+ assert_equal decoded[1]["alg"], "RS256"
96
+ assert_equal decoded[1]["kid"], jwk.export[:kid]
97
+
98
+ assert is_uuid?(decoded[0]["x-roku-request-key"])
99
+ spec = decoded[0]["x-roku-request-spec"]
100
+ refute_nil spec
101
+ assert_equal spec["serviceUrn"], urn
102
+ assert_equal spec["httpMethod"], method
103
+ assert_equal spec["path"], path
104
+ end
105
+
106
+ def test_get_jwt_token_with_body
107
+ api = RokuAPI.new(config: @config)
108
+ urn = "test:urn"
109
+ method = "GET"
110
+ path = "/test/path"
111
+ body = {
112
+ "appFileBase64Encoded" => Base64.encode64(File.open(File.join(test_files_path(RokuAPITest), "test.pkg")).read)
113
+ }
114
+ sha256 = Digest::SHA256.base64digest(body.to_json)
115
+ token = api.send(:get_jwt_token, @options[:api_key], urn, method, path, body.to_json)
116
+ jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
117
+ decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
118
+ assert_equal decoded[1]["typ"], "JWT"
119
+ assert_equal decoded[1]["alg"], "RS256"
120
+ assert_equal decoded[1]["kid"], jwk.export[:kid]
121
+
122
+ assert is_uuid?(decoded[0]["x-roku-request-key"])
123
+ spec = decoded[0]["x-roku-request-spec"]
124
+ refute_nil spec
125
+ assert_equal spec["serviceUrn"], urn
126
+ assert_equal spec["httpMethod"], method
127
+ assert_equal spec["path"], path
128
+ assert_equal spec["bodySha256Base64"], sha256
129
+ end
130
+
131
+ def test_api_get
132
+ api = RokuAPI.new(config: @config)
133
+ path = "/test/path"
134
+ api.instance_variable_set(:@api_key, "key1")
135
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
136
+ response = api.send(:api_get, path)
137
+ assert_requested(:get, "https://apipub.roku.com/developer/v1/test/path", headers: {
138
+ "Accept" => "application/json",
139
+ "Content-Type" => "application/json",
140
+ "Authorization" => /Bearer .*/
141
+ })
142
+ end
143
+
144
+ def test_api_post
145
+ api = RokuAPI.new(config: @config)
146
+ path = "/test/path"
147
+ token_path = "/other/path"
148
+ api.instance_variable_set(:@api_key, "key1")
149
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
150
+ encoded = Base64.encode64(package.read)
151
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
152
+ called = false
153
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
154
+ called = true
155
+ assert_equal path, token_path
156
+ "token"
157
+ end
158
+ params = {"status" => "Published"}
159
+ api.stub(:get_jwt_token, jwt_proc) do
160
+ response = api.send(:api_post, path, token_path, package, params)
161
+ end
162
+ assert called
163
+ assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
164
+ body: {"appFileBase64Encoded" => encoded}.to_json,
165
+ headers: {
166
+ "Accept" => "application/json",
167
+ "Content-Type" => "application/json",
168
+ "Authorization" => /Bearer token/
169
+ },
170
+ query: {"status" => "Published"}
171
+ )
172
+ end
173
+
174
+ def test_api_post_no_package
175
+ api = RokuAPI.new(config: @config)
176
+ path = "/test/path"
177
+ token_path = "/other/path"
178
+ api.instance_variable_set(:@api_key, "key1")
179
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
180
+ called = false
181
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
182
+ called = true
183
+ assert_equal path, token_path
184
+ "token"
185
+ end
186
+ api.stub(:get_jwt_token, jwt_proc) do
187
+ response = api.send(:api_post, path, token_path)
188
+ end
189
+ assert called
190
+ assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
191
+ headers: {
192
+ "Accept" => "application/json",
193
+ "Content-Type" => "application/json",
194
+ "Authorization" => /Bearer .*/
195
+ }
196
+ )
197
+ end
198
+
199
+ def test_api_patch
200
+ api = RokuAPI.new(config: @config)
201
+ path = "/test/path"
202
+ token_path = "/other/path"
203
+ api.instance_variable_set(:@api_key, "key1")
204
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
205
+ encoded = Base64.encode64(package.read)
206
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
207
+ called = false
208
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
209
+ called = true
210
+ assert_equal path, token_path
211
+ "token"
212
+ end
213
+ api.stub(:get_jwt_token, jwt_proc) do
214
+ response = api.send(:api_patch, path, token_path, package)
215
+ end
216
+ assert called
217
+ assert_requested(:patch, "https://apipub.roku.com/developer/v1/test/path",
218
+ body: {"path" => "/appFileBase64Encoded", "value" => encoded, "op" => "replace"}.to_json,
219
+ headers: {
220
+ "Accept" => "application/json",
221
+ "Content-Type" => "application/json",
222
+ "Authorization" => /Bearer token/
223
+ }
224
+ )
225
+ end
226
+
227
+ def test_get_channel_versions
228
+ api = RokuAPI.new(config: @config)
229
+ channel = "1234"
230
+ api.instance_variable_set(:@api_key, "key1")
231
+ response = Minitest::Mock.new
232
+ body = { "id" => "1234", "version" => "1.1"}
233
+ response.expect(:body, body.to_json)
234
+ called = 0
235
+ get_proc = proc do |path|
236
+ called +=1
237
+ assert_equal path, "/external/channels/#{channel}/versions"
238
+ response
239
+ end
240
+ sort_proc = proc do |versions|
241
+ called += 1
242
+ versions
243
+ end
244
+ api.stub(:api_get, get_proc) do
245
+ api.stub(:sorted_versions, sort_proc) do
246
+ result = api.send(:get_channel_versions, channel)
247
+ assert_equal result, body
248
+ end
249
+ end
250
+ assert_equal 2, called
251
+ end
252
+
253
+ def test_submit_no_channel_id
254
+ api = RokuAPI.new(config: @config)
255
+ assert_raises RokuBuilder::InvalidOptions do
256
+ api.submit(options: {})
257
+ end
258
+ end
259
+
260
+ def test_submit_without_unpublished
261
+ api = RokuAPI.new(config: @config)
262
+ called = {}
263
+ @options[:no_publish] = true
264
+ response = Minitest::Mock.new
265
+ response.expect(:success?, true)
266
+ response.expect(:body, api_versions[0].to_json)
267
+ updated = proc {called[:updated] = true; response}
268
+ created = proc {called[:created] = true; response}
269
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
270
+ body: api_versions.to_json
271
+ ))
272
+ api.stub(:create_channel_version, created) do
273
+ api.stub(:update_channel_version, updated) do
274
+ api.stub(:get_package, "") do
275
+ api.submit(options: @options)
276
+ end
277
+ end
278
+ end
279
+ assert called[:created]
280
+ assert_nil called[:updated]
281
+ assert api.instance_variable_get(:@no_publish)
282
+
283
+ end
284
+ def test_submit_without_latest_unpublished
285
+ api = RokuAPI.new(config: @config)
286
+ called = {}
287
+ body = api_versions
288
+ body.push(api_versions.first)
289
+ body[1]["version"] = "1.3"
290
+ body[1]["channelState"] = "Unpublished"
291
+ body[1]["createdDate"] = (DateTime.now -10).to_s
292
+ response = Minitest::Mock.new
293
+ response.expect(:success?, true)
294
+ response.expect(:body, body[0].to_json)
295
+ updated = proc {called[:updated] = true; response}
296
+ created = proc {called[:created] = true; response}
297
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
298
+ body: body.to_json
299
+ ))
300
+ api.stub(:create_channel_version, created) do
301
+ api.stub(:update_channel_version, updated) do
302
+ api.stub(:get_package, "") do
303
+ api.submit(options: @options)
304
+ end
305
+ end
306
+ end
307
+ assert called[:created]
308
+ assert_nil called[:updated]
309
+ end
310
+
311
+ def test_submit_with_unpublished
312
+ api = RokuAPI.new(config: @config)
313
+ body = api_versions
314
+ body[0]["channelState"] = "Unpublished"
315
+ called = {}
316
+ response = Minitest::Mock.new
317
+ response.expect(:success?, true)
318
+ response.expect(:body, body[0].to_json)
319
+ updated = proc do |channel, package, version|
320
+ called[:updated] = true
321
+ assert_equal body[0]["id"], version
322
+ response
323
+ end
324
+ created = proc {called[:created] = true; response}
325
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
326
+ body: body.to_json
327
+ ))
328
+ api.stub(:create_channel_version, created) do
329
+ api.stub(:update_channel_version, updated) do
330
+ api.stub(:get_package, "") do
331
+ api.submit(options: @options)
332
+ end
333
+ end
334
+ end
335
+ assert called[:updated]
336
+ assert_nil called[:created]
337
+ end
338
+
339
+ def test_create_channel_version
340
+ api = RokuAPI.new(config: @config)
341
+ channel = "1234"
342
+ api.instance_variable_set(:@api_key, "key1")
343
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
344
+ called = false
345
+ post_proc = proc do |path, token_path, package, params|
346
+ called = true
347
+ assert_equal path, "/external/channels/#{channel}/versions"
348
+ assert_equal token_path, "/external/channels/#{channel}/versions"
349
+ assert_equal "Published", params["channelState"]
350
+ assert_kind_of File, package
351
+ end
352
+ api.stub(:api_post, post_proc) do
353
+ api.send(:create_channel_version, channel, package)
354
+ end
355
+ assert called
356
+ end
357
+
358
+ def test_create_channel_version_no_publish
359
+ api = RokuAPI.new(config: @config)
360
+ channel = "1234"
361
+ api.instance_variable_set(:@api_key, "key1")
362
+ api.instance_variable_set(:@no_publish, true)
363
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
364
+ called = false
365
+ post_proc = proc do |path, token_path, package, params|
366
+ called = true
367
+ assert_equal path, "/external/channels/#{channel}/versions"
368
+ assert_equal token_path, "/external/channels/#{channel}/versions"
369
+ assert_nil params
370
+ assert_kind_of File, package
371
+ end
372
+ api.stub(:api_post, post_proc) do
373
+ api.send(:create_channel_version, channel, package)
374
+ end
375
+ assert called
376
+ end
377
+
378
+ def test_update_channel_version
379
+ api = RokuAPI.new(config: @config)
380
+ channel = "1234"
381
+ version = "1234"
382
+ api.instance_variable_set(:@api_key, "key1")
383
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
384
+ called = false
385
+ patch_proc = proc do |path, token_path, package|
386
+ called = true
387
+ assert_equal path, "/external/channel/#{channel}/#{version}"
388
+ assert_equal token_path, "/external/channels/#{channel}/#{version}"
389
+ assert_kind_of File, package
390
+ end
391
+ api.stub(:api_patch, patch_proc) do
392
+ api.send(:update_channel_version, channel, package, version)
393
+ end
394
+ assert called
395
+ end
396
+
397
+ def test_publish_no_channel_id
398
+ api = RokuAPI.new(config: @config)
399
+ assert_raises RokuBuilder::InvalidOptions do
400
+ params = {options: {}}
401
+ api.send(:publish, **params)
402
+ end
403
+ end
404
+
405
+ def test_publish_without_unpublished
406
+ api = RokuAPI.new(config: @config)
407
+ expected_channel = "1234"
408
+ api.instance_variable_set(:@api_key, "key1")
409
+ body = api_versions
410
+ called = false
411
+ get_proc = proc do |channel|
412
+ called = true
413
+ assert_equal expected_channel, channel
414
+ body
415
+ end
416
+ api.stub(:get_channel_versions, get_proc) do
417
+ assert_raises RokuBuilder::ExecutionError do
418
+ params = {options: {channel_id: expected_channel}}
419
+ api.send(:publish, **params)
420
+ end
421
+ end
422
+ assert called
423
+ end
424
+
425
+ def test_publish_without_latest_unpublished
426
+ api = RokuAPI.new(config: @config)
427
+ expected_channel = "1234"
428
+ api.instance_variable_set(:@api_key, "key1")
429
+ body = api_versions
430
+ body.push(api_versions.first)
431
+ body[1]["version"] = "1.3"
432
+ body[1]["channelState"] = "Unpublished"
433
+ called = false
434
+ get_proc = proc do |channel|
435
+ called = true
436
+ assert_equal expected_channel, channel
437
+ body
438
+ end
439
+ api.stub(:get_channel_versions, get_proc) do
440
+ assert_raises RokuBuilder::ExecutionError do
441
+ params = {options: {channel_id: expected_channel}}
442
+ api.send(:publish, **params)
443
+ end
444
+ end
445
+ assert called
446
+ end
447
+
448
+ def test_publish_with_unpublished
449
+ api = RokuAPI.new(config: @config)
450
+ expected_channel = "1234"
451
+ api.instance_variable_set(:@api_key, "key1")
452
+ body = [{ "id" => "1234", "version" => "1.1", "channelState" => "Unpublished"}]
453
+ called = 0
454
+ get_proc = proc do |channel|
455
+ called += 1
456
+ assert_equal expected_channel, channel
457
+ body
458
+ end
459
+ response = Minitest::Mock.new
460
+ response.expect(:success?, true)
461
+ response.expect(:body, body[0].to_json)
462
+ post_proc = proc do |channel, version|
463
+ called += 1
464
+ assert_equal expected_channel, channel
465
+ assert_equal body.first["id"], version
466
+ response
467
+ end
468
+ api.stub(:get_channel_versions, get_proc) do
469
+ api.stub(:publish_channel_version, post_proc) do
470
+ params = {options: {channel_id: expected_channel}}
471
+ api.send(:publish, **params)
472
+ end
473
+ end
474
+ assert_equal called, 2
475
+ end
476
+
477
+ def test_publish_channel_version
478
+ api = RokuAPI.new(config: @config)
479
+ channel = "1234"
480
+ api.instance_variable_set(:@api_key, "key1")
481
+ response = Minitest::Mock.new
482
+ body = { "id" => "1234", "version" => "1.1"}
483
+ response.expect(:body, body.to_json)
484
+ called = false
485
+ post_proc = proc do |path, token_path|
486
+ called = true
487
+ assert_equal path, "/external/channels/#{channel}/versions/#{body["id"]}"
488
+ assert_equal token_path, "/external/channels/#{channel}/versions/#{body["id"]}/state"
489
+ end
490
+ api.stub(:api_post, post_proc) do
491
+ api.send(:publish_channel_version, channel, body["id"])
492
+ end
493
+ assert called
494
+ end
495
+
496
+ def test_submit_failure_create
497
+ api = RokuAPI.new(config: @config)
498
+ response = Minitest::Mock.new
499
+ response.expect(:success?, false)
500
+ response.expect(:reason_phrase, "reason")
501
+ api.stub(:get_channel_versions, api_versions) do
502
+ api.stub(:create_channel_version, response) do
503
+ api.stub(:get_package, "") do
504
+ assert_raises RokuBuilder::ExecutionError do
505
+ api.submit(options: @options)
506
+ end
507
+ end
508
+ end
509
+ end
510
+ assert_mock response
511
+ end
512
+
513
+ def test_submit_response_created
514
+ api = RokuAPI.new(config: @config)
515
+ body = { "id" => "1234", "version" => "1.1"}
516
+ response = Minitest::Mock.new
517
+ response.expect(:success?, true)
518
+ response.expect(:body, body.to_json)
519
+ api.stub(:get_channel_versions, api_versions) do
520
+ api.stub(:create_channel_version, response) do
521
+ api.stub(:get_package, "") do
522
+ response_json = api.submit(options: @options)
523
+ assert_equal body, response_json
524
+ end
525
+ end
526
+ end
527
+ assert_mock response
528
+ end
529
+
530
+ def test_submit_response_updated
531
+ api = RokuAPI.new(config: @config)
532
+ body = { "id" => "1234", "version" => "1.1"}
533
+ response = Minitest::Mock.new
534
+ response.expect(:success?, true)
535
+ response.expect(:body, body.to_json)
536
+ versions = api_versions
537
+ versions[0]["channelState"] = "Unpublished"
538
+ api.stub(:get_channel_versions, versions) do
539
+ api.stub(:update_channel_version, response) do
540
+ api.stub(:get_package, "") do
541
+ response_json = api.submit(options: @options)
542
+ assert_equal body, response_json
543
+ end
544
+ end
545
+ end
546
+ assert_mock response
547
+ end
548
+
549
+ def test_publish_response
550
+ api = RokuAPI.new(config: @config)
551
+ body = { "id" => "1234", "version" => "1.1"}
552
+ response = Minitest::Mock.new
553
+ response.expect(:success?, true)
554
+ response.expect(:body, body.to_json)
555
+ versions = api_versions
556
+ versions[0]["channelState"] = "Unpublished"
557
+ api.stub(:get_channel_versions, versions) do
558
+ api.stub(:publish_channel_version, response) do
559
+ response_json = api.publish(options: @options)
560
+ assert_equal body, response_json
561
+ end
562
+ end
563
+ assert_mock response
564
+ end
565
+ end
566
+ end
@@ -44,6 +44,22 @@ module RokuBuilder
44
44
  assert_equal File.join(Dir.pwd, "infile"), configs[:root_dir]
45
45
  end
46
46
 
47
+ def test_api_keys
48
+ options = build_options({
49
+ current: true,
50
+ validate: true
51
+ })
52
+ config = good_config(ConfigParserTest)
53
+ configs = nil
54
+ File.stub(:exist?, true) do
55
+ configs = ConfigParser.parse(options: options, config: config)
56
+ end
57
+
58
+ assert_kind_of Hash, configs
59
+ assert_kind_of Hash, configs[:api_keys]
60
+ assert_equal configs[:api_keys][:key1], File.join(test_files_path(ConfigParserTest), "test_key.json")
61
+ end
62
+
47
63
  def test_manifest_config_current
48
64
  options = build_options({
49
65
  current: true,
@@ -216,5 +216,19 @@ module RokuBuilder
216
216
  validator = ConfigValidator.new(config: config)
217
217
  assert_equal [12], validator.instance_variable_get(:@codes)
218
218
  end
219
+
220
+ def test_config_validate_invalid_api_key
221
+ config = good_config
222
+ config[:api_keys][:key1] = nil
223
+ validator = ConfigValidator.new(config: config)
224
+ assert_equal [22], validator.instance_variable_get(:@codes)
225
+ end
226
+
227
+ def test_confif_validate_no_api_keys
228
+ config = good_config
229
+ config[:api_keys] = nil
230
+ validator = ConfigValidator.new(config: config)
231
+ assert_equal [0], validator.instance_variable_get(:@codes)
232
+ end
219
233
  end
220
234
  end
@@ -39,7 +39,7 @@ module RokuBuilder
39
39
  @ping.expect(:ping?, false, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
40
40
  manager = DeviceManager.new(config: config, options: options)
41
41
  assert_raises(DeviceError) do
42
- device = manager.reserve_device
42
+ manager.reserve_device
43
43
  end
44
44
  end
45
45
  end
@@ -50,9 +50,9 @@ module RokuBuilder
50
50
  @ping.expect(:ping?, true, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
51
51
  @ping.expect(:ping?, true, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
52
52
  manager = DeviceManager.new(config: config, options: options)
53
- device1 = manager.reserve_device
53
+ manager.reserve_device
54
54
  assert_raises(DeviceError) do
55
- device2 = manager.reserve_device
55
+ manager.reserve_device
56
56
  end
57
57
  end
58
58
  end
@@ -121,7 +121,7 @@ module RokuBuilder
121
121
  manager = DeviceManager.new(config: config, options: options)
122
122
  device1 = manager.reserve_device
123
123
  assert_raises(DeviceError) do
124
- device2 = manager.reserve_device
124
+ manager.reserve_device
125
125
  end
126
126
  assert_equal "test2", device1.name
127
127
  end
@@ -0,0 +1,13 @@
1
+ {
2
+ "kty": "RSA",
3
+ "kid": "hbdk0JpkFRc39Dx7WXxKkntR0UeCp-J7PiWWkwGOaHk",
4
+ "alg": "RS256",
5
+ "e": "AQAB",
6
+ "n": "xRFv0nywIFBexub60g-bi4ZwEOj_E-bA_bqO99w6kbAMu_XqAvYaIu2StZK1SedrK-kKcOCXFfEbCGlM0CZnrIXU5usRERvS1dDUZz3KyJ9DPi4VMUgTTONM6m_NrfgOa8-V71LcNXcnQ2ZhWTvffcvgZ7Btz0yMbuwhIKlJNEs9MtrZDV_yWpbns-kQDH1A3PS22ZNGej7ifJJuIX1KitDLvkjrYR8MaCf-PUJewU-7ugpvO1pNi6ChYcTY09YuScPYiZg5i9yClve0lwScw2DBIBMfxyAG626YZtUkv6ffKQuceak-w0vx7gYLOJv_aCyKNcxrmFmMYwDIbXDaHQ",
7
+ "d": "G0wdBzUKWI-JcVfRaoOK8jq_DziXDLSsCvlqkF7LJh8SxH592ccpO6lY5xnZTtFlgQGY1qXlh76MFhAv-a04MyeepBXvmUUXYVK5-UsP6dZVxCkx-k-XjND3eIngHbb8mGZ6yFnb8vP8VlO6LFgkzxIMlZBUxaA-26aNuC5622lKUoQQiD3eVxu93hIOAjn08dMn4yl8D4MbD8kfkWeQIXM0VI25YjKlt2mJSajyMxxMFTIrevoGo72tEgjpER--EDXMBuq0KsPSU7ZHfLhs6Dk2bcG79JAZ4WG17gkoO1atjta_kPXik4MQEeQYFgT3kaLSsSvhv3ipp28nOwFugQ",
8
+ "p": "7OeIV6zOUlyWcNvX4uwRy_qKo-JAltmSqIiTQmry9l2HDFEV3hnPnV5uyYU6uIo-OWMTWxWR_41Wl45Na15DYhcY8ttudAseiPHPqczhbm5jCzYSt6vY4prKDMXP3rXbRb9wGPm22BqU-ERxQz_vwMhXxDhLaHjOZ3ihjcFI440",
9
+ "q": "1PPkKEGmegHkH7YPXoZyz90qk2FRBBY76ulU-ThXaaMDiS0vDJqcwrvpk9UDT3hdnZhh0zLhlS1C9ypvnQDqTA7p8h_my0VL9bXVcEgUzzkgQ_Vjyq9-6Lb2y9HGqXUoycLS4xss5qXZOM26oFGkeRgfGXZo2Ndlb-zGQN88ZNE",
10
+ "dp": "2Q1FGPclzcYwu9RglvMtVxMEpSRtgwhy22DOcwLj-h801W8RNv20_3z-yjn71Aos-o0wtbosmtRXKuJhQmcKG7wHyrKLH1z0rAnI9szVGkWfDy2KtqeHPg8N4ef3DRjXfq7oOKnKAXNRW6nxj-jrdFjaONhPFrfgfGLEuckGTB0",
11
+ "dq": "HWWZrnD5oUgXjMUeNAdNXCKE2RmLDIxhMxmI0GqVrpCBUXN6VjwVvdAg-3ZhYZwVGEdL4dLZTzWTU_l4tOzGaz93ziPXQWJMjRvP3hMlREH3kUoTv4wgcdGoGhTYXtY8jjWl1RIQTbrBVNUZmT4L_Wd2C5bL_Hsnlp7R82ydsrE",
12
+ "qi": "cnrYQq21HMSlYj3Ga_F8Su1H_9cKjZPJoeRcGagkBQpIx2zGxhheTEXZV7X9RFNyLev6zBXxue6PEhjAEEDqlNKNFXSmlLSkbDkKCMb1yeALTPSqrNFvq8DdH0cxMDTPI0U5K2JCwuAoAyXzWxENEiRlq4oizdzZBvilM7TF4fM"
13
+ }
@@ -71,56 +71,80 @@ def tmp_folder()
71
71
  Dir.tmpdir()
72
72
  end
73
73
 
74
+ def is_uuid?(uuid)
75
+ uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
76
+ return true if uuid_regex.match?(uuid.to_s.downcase)
77
+ false
78
+ end
79
+
74
80
  def good_config(klass=nil)
75
81
  root_dir = "/tmp"
76
82
  root_dir = test_files_path(klass) if klass
77
83
  {
78
84
  devices: {
79
- default: :roku,
80
- roku: {
81
- ip: "192.168.0.100",
82
- user: "user",
83
- password: "password"
84
- }
85
- },
85
+ default: :roku,
86
+ roku: {
87
+ ip: "192.168.0.100",
88
+ user: "user",
89
+ password: "password"
90
+ }
91
+ },
86
92
  projects: {
87
- default: :project1,
88
- project1: {
89
- directory: root_dir,
90
- source_files: ["manifest", "images", "source"],
91
- app_name: "<app name>",
92
- stage_method: :git,
93
- stages:{
94
- production: {
95
- branch: "production",
96
- key: {
97
- keyed_pkg: File.join(root_dir, "test.pkg"),
98
- password: "password"
99
- }
100
- }
101
- }
102
- },
103
- project2: {
104
- directory: root_dir,
105
- source_files: ["images","source","manifest"],
106
- app_name: "<app name>",
107
- stage_method: :script,
108
- stages:{
109
- production: {
110
- script: {stage: "stage_script", unstage: "unstage_script"},
111
- key: "a"
112
- }
113
- }
114
- }
115
- },
93
+ default: :project1,
94
+ project1: {
95
+ directory: root_dir,
96
+ source_files: ["manifest", "images", "source"],
97
+ app_name: "<app name>",
98
+ stage_method: :git,
99
+ stages:{
100
+ production: {
101
+ branch: "production",
102
+ key: {
103
+ keyed_pkg: File.join(root_dir, "test.pkg"),
104
+ password: "password"
105
+ }
106
+ }
107
+ }
108
+ },
109
+ project2: {
110
+ directory: root_dir,
111
+ source_files: ["images","source","manifest"],
112
+ app_name: "<app name>",
113
+ stage_method: :script,
114
+ stages:{
115
+ production: {
116
+ script: {stage: "stage_script", unstage: "unstage_script"},
117
+ key: "a"
118
+ }
119
+ }
120
+ }
121
+ },
116
122
  keys: {
117
- a: {
118
- keyed_pkg: File.join(root_dir, "test.pkg"),
119
- password: "password"
120
- }
121
- },
123
+ a: {
124
+ keyed_pkg: File.join(root_dir, "test.pkg"),
125
+ password: "password"
126
+ }
127
+ },
122
128
  input_mappings: {
123
- "a": ["home", "Home"]
124
- }
129
+ "a": ["home", "Home"]
130
+ },
131
+ api_keys: {
132
+ key1: File.join(root_dir, "test_key.json")
133
+ }
125
134
  }
126
135
  end
136
+
137
+ def api_versions
138
+ [
139
+ {
140
+ "id" => "5735B375-2607-435F-97AE-66954DC2A91F",
141
+ "channelState" => "Published",
142
+ "appSize" => 1226192,
143
+ "channelId" => 722085,
144
+ "version" => "1.4",
145
+ "minFirmwareVersion" => 0,
146
+ "minimumFirmwareVersionTextShort" => "v2.5 b388",
147
+ "createdDate" => DateTime.now.to_s
148
+ }
149
+ ]
150
+ end
@@ -10,12 +10,12 @@ class GitTest < Minitest::Test
10
10
 
11
11
  index = 1
12
12
  base.expect(:lib, lib)
13
+ base.expect(:lib, lib)
14
+ lib.expect(:stashes_all, [])
13
15
  lib.expect(:stash_pop, nil, [index])
14
16
 
15
17
  Dir.mktmpdir do |dir|
16
- git = Git.init(File.join(dir, "git"))
17
- stashes = git.branch.stashes
18
- stashes.instance_variable_set(:@base, base)
18
+ stashes = Git::Stashes.new(base)
19
19
  stashes.pop(index)
20
20
  end
21
21
 
@@ -29,12 +29,12 @@ class GitTest < Minitest::Test
29
29
 
30
30
  index = 1
31
31
  base.expect(:lib, lib)
32
+ base.expect(:lib, lib)
33
+ lib.expect(:stashes_all, [])
32
34
  lib.expect(:stash_drop, nil, [index])
33
35
 
34
36
  Dir.mktmpdir do |dir|
35
- git = Git.init(File.join(dir, "git"))
36
- stashes = git.branch.stashes
37
- stashes.instance_variable_set(:@base, base)
37
+ stashes = Git::Stashes.new(base)
38
38
  stashes.drop(index)
39
39
  end
40
40
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: roku_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.28.0
4
+ version: 4.29.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - greeneca
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-09 00:00:00.000000000 Z
11
+ date: 2024-01-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
152
  version: '2.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: jwt
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.7'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.7'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: bundler
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -514,6 +528,7 @@ files:
514
528
  - lib/roku_builder/plugins/packager.rb
515
529
  - lib/roku_builder/plugins/performance_config.json
516
530
  - lib/roku_builder/plugins/profiler.rb
531
+ - lib/roku_builder/plugins/rokuapi.rb
517
532
  - lib/roku_builder/plugins/sca-cmd/LICENSE
518
533
  - lib/roku_builder/plugins/sca-cmd/README.md
519
534
  - lib/roku_builder/plugins/sca-cmd/bin/sca-cmd
@@ -536,6 +551,7 @@ files:
536
551
  - test/roku_builder/plugins/test_navigator.rb
537
552
  - test/roku_builder/plugins/test_packager.rb
538
553
  - test/roku_builder/plugins/test_profiler.rb
554
+ - test/roku_builder/plugins/test_rokuapi.rb
539
555
  - test/roku_builder/plugins/test_scripter.rb
540
556
  - test/roku_builder/plugins/test_tester.rb
541
557
  - test/roku_builder/test_config.rb
@@ -614,6 +630,8 @@ files:
614
630
  - test/roku_builder/test_files/packager_test/manifest
615
631
  - test/roku_builder/test_files/packager_test/scripter_test/manifest
616
632
  - test/roku_builder/test_files/packager_test/test.pkg
633
+ - test/roku_builder/test_files/roku_api_test/test.pkg
634
+ - test/roku_builder/test_files/roku_api_test/test_key.json
617
635
  - test/roku_builder/test_files/roku_builder_test/config.json
618
636
  - test/roku_builder/test_files/scripter_test/manifest
619
637
  - test/roku_builder/test_files/scripter_test/test.pkg
@@ -667,6 +685,7 @@ test_files:
667
685
  - test/roku_builder/plugins/test_navigator.rb
668
686
  - test/roku_builder/plugins/test_packager.rb
669
687
  - test/roku_builder/plugins/test_profiler.rb
688
+ - test/roku_builder/plugins/test_rokuapi.rb
670
689
  - test/roku_builder/plugins/test_scripter.rb
671
690
  - test/roku_builder/plugins/test_tester.rb
672
691
  - test/roku_builder/test_config.rb
@@ -745,6 +764,8 @@ test_files:
745
764
  - test/roku_builder/test_files/packager_test/manifest
746
765
  - test/roku_builder/test_files/packager_test/scripter_test/manifest
747
766
  - test/roku_builder/test_files/packager_test/test.pkg
767
+ - test/roku_builder/test_files/roku_api_test/test.pkg
768
+ - test/roku_builder/test_files/roku_api_test/test_key.json
748
769
  - test/roku_builder/test_files/roku_builder_test/config.json
749
770
  - test/roku_builder/test_files/scripter_test/manifest
750
771
  - test/roku_builder/test_files/scripter_test/test.pkg