roku_builder 4.27.2 → 4.29.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: efc602510a82d3cff193e13043545a4ce51ce65cc44efe011e95bfac75a6a820
4
- data.tar.gz: b9d38640ea2be785eb4fc370216ab6f8cb82edf6e54027eed2a3abd2812a0c4a
3
+ metadata.gz: a74435c26dad5e136130516be10f397638bb374f4f105a8ca25c438193b39151
4
+ data.tar.gz: 1fa12ee0b271ae1506b5d3ffe028da016fbafa208eee996b6f9fbedd5dbb3a0e
5
5
  SHA512:
6
- metadata.gz: ad5fa526a32f9fa53e12d78d6243eb2381c5b8c7c43877718c319c8eb70537eda7de8f649de242611155f1638f3730ea51cd5543d94d69b181d1c527d331b36a
7
- data.tar.gz: e7bdab7f64cdbb74bc0bcae86b8c6d5b6b551ac4da95b0e547562470022bb32b25b3744a91e6f148a577eeb4ebd52093a86972e90e5ca07c517cb8abb88d08d8
6
+ metadata.gz: a7a74b63df763ff355473e8f1d5e90c80ea0805c8539edf43d189199876ebf7fd801322e45020ae9192c888c53e9de39f2e23d2ebe95ce581a4e0016fb2db493
7
+ data.tar.gz: 202e8b749f4b0aa46d6a0ebd18aabae4a3c486214d5945b823e1cc897b0a36a1ed3d351c07f0e49bf89e612df92bed68d860d3b1797ff89a92af63a9c3bd8313
@@ -23,7 +23,8 @@ module RokuBuilder
23
23
  load_config
24
24
  end
25
25
 
26
- def parse(stage: nil)
26
+ def parse(stage: nil, options: nil)
27
+ @options = options if options
27
28
  @options[:stage] = stage if stage
28
29
  @parsed = ConfigParser.parse(options: @options, config: @config)
29
30
  end
@@ -126,7 +127,6 @@ module RokuBuilder
126
127
  if File.exist?(local_config_path) and !@loaded_configs.include?(File.expand_path(local_config_path))
127
128
  local_config_hash = read_config(File.open(local_config_path))
128
129
  add_missing_directories(local_config_hash)
129
- local_sub_configs = "./.roku_config/*.json"
130
130
  @config = @config.deep_merge(local_config_hash)
131
131
  Dir.glob("./.roku_config/*.json").each do |sub_config_path|
132
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,184 @@
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
+ aa, ab = a["version"].split(".").map{|i| i.to_i}
90
+ ba, bb = b["version"].split(".").map{|i| i.to_i}
91
+ value = (aa == ba ? bb <=> ab : ba <=> aa)
92
+ value
93
+ end
94
+ sorted
95
+ end
96
+
97
+ def create_channel_version(channel, package)
98
+ path = "/external/channels/#{channel}/versions"
99
+ params = nil
100
+ unless @no_publish
101
+ params = {"channelState" => "Published"}
102
+ end
103
+ api_post(path, path, package, params)
104
+ end
105
+
106
+ def update_channel_version(channel, package, version)
107
+ path = "/external/channel/#{channel}/#{version}"
108
+ token_path = "/external/channels/#{channel}/#{version}"
109
+ api_patch(path, token_path, package)
110
+ end
111
+
112
+ def publish_channel_version(channel, version)
113
+ path = "/external/channels/#{channel}/versions/#{version}"
114
+ token_path = "/external/channels/#{channel}/versions/#{version}/state"
115
+ api_post(path, token_path)
116
+ end
117
+
118
+ def api_get(path)
119
+ service_urn = "urn:roku:cloud-services:chanprovsvc"
120
+ connection('GET', path, nil).get(api_path+path)
121
+ end
122
+
123
+ def api_post(path, token_path, package=nil, params = nil)
124
+ body = {}.to_json
125
+ if package
126
+ body = {
127
+ "appFileBase64Encoded" => Base64.encode64(package.read)
128
+ }.to_json
129
+ end
130
+ connection('POST', token_path, body).post(api_path+path) do |request|
131
+ if params
132
+ request.params = params
133
+ end if
134
+ request.body = body
135
+ end
136
+ end
137
+
138
+ def api_patch(path, token_path, package)
139
+ body = {
140
+ "path" => "/appFileBase64Encoded",
141
+ "value" => Base64.encode64(package.read),
142
+ "op" => "replace"
143
+ }.to_json
144
+ response = connection('PATCH', token_path, body).patch(api_path+path) do |request|
145
+ request.body = body
146
+ end
147
+ end
148
+
149
+ def connection(method, path, body)
150
+ service_urn = "urn:roku:cloud-services:chanprovsvc"
151
+ connection = Faraday.new(url: HOST, headers: {
152
+ 'Authorization' => "Bearer "+get_jwt_token(@api_key, service_urn, method, path, body),
153
+ 'Content-Type' => 'application/json',
154
+ 'Accept' => 'application/json',
155
+ }) do |f|
156
+ f.adapter Faraday.default_adapter
157
+ end
158
+ end
159
+
160
+ def get_jwt_token(api_key, service_urn, method, path, body = nil)
161
+ key_file = File.expand_path(@config.api_keys[api_key.to_sym])
162
+ raise InvalidOptions "Missing api key" unless key_file
163
+ jwk = JWT::JWK.new(JSON.parse(File.read(key_file)))
164
+ header = {
165
+ "typ" => "JWT",
166
+ "kid" => jwk.export[:kid]
167
+ }
168
+ payload = {
169
+ "exp" => (Time.now + (12*60*60)).to_i,
170
+ "x-roku-request-key" => SecureRandom.uuid,
171
+ "x-roku-request-spec" => {
172
+ "serviceUrn" => service_urn,
173
+ "httpMethod" => method,
174
+ "path" => path,
175
+ }
176
+ }
177
+ if body
178
+ payload["x-roku-request-spec"]["bodySha256Base64"] = Digest::SHA256.base64digest(body)
179
+ end
180
+ JWT.encode(payload, jwk.signing_key, 'RS256', header)
181
+ end
182
+ end
183
+ RokuBuilder.register_plugin(RokuAPI)
184
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module RokuBuilder
4
4
  # Version of the RokuBuilder Gem
5
- VERSION = "4.27.2"
5
+ VERSION = "4.29.1"
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,557 @@
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 = [{"version" => "1.9"}, {"version" => "1.11"}, {"version" => "2.3"}, {"version" => "2.4"}]
67
+ sorted = api.send(:sorted_versions, versions)
68
+ assert_equal "2.4", sorted[0]["version"]
69
+ assert_equal "2.3", sorted[1]["version"]
70
+ assert_equal "1.11", sorted[2]["version"]
71
+ assert_equal "1.9", sorted[3]["version"]
72
+ versions = [{"version" => "1.4"}, {"version" => "1.3"}]
73
+ sorted = api.send(:sorted_versions, versions)
74
+ assert_equal "1.4", sorted[0]["version"]
75
+ assert_equal "1.3", sorted[1]["version"]
76
+ end
77
+
78
+ def test_get_jwt_token
79
+ api = RokuAPI.new(config: @config)
80
+ urn = "test:urn"
81
+ method = "GET"
82
+ path = "/test/path"
83
+ token = api.send(:get_jwt_token, @options[:api_key], urn, method, path)
84
+ jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
85
+ decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
86
+ assert_equal decoded[1]["typ"], "JWT"
87
+ assert_equal decoded[1]["alg"], "RS256"
88
+ assert_equal decoded[1]["kid"], jwk.export[:kid]
89
+
90
+ assert is_uuid?(decoded[0]["x-roku-request-key"])
91
+ spec = decoded[0]["x-roku-request-spec"]
92
+ refute_nil spec
93
+ assert_equal spec["serviceUrn"], urn
94
+ assert_equal spec["httpMethod"], method
95
+ assert_equal spec["path"], path
96
+ end
97
+
98
+ def test_get_jwt_token_with_body
99
+ api = RokuAPI.new(config: @config)
100
+ urn = "test:urn"
101
+ method = "GET"
102
+ path = "/test/path"
103
+ body = {
104
+ "appFileBase64Encoded" => Base64.encode64(File.open(File.join(test_files_path(RokuAPITest), "test.pkg")).read)
105
+ }
106
+ sha256 = Digest::SHA256.base64digest(body.to_json)
107
+ token = api.send(:get_jwt_token, @options[:api_key], urn, method, path, body.to_json)
108
+ jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
109
+ decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
110
+ assert_equal decoded[1]["typ"], "JWT"
111
+ assert_equal decoded[1]["alg"], "RS256"
112
+ assert_equal decoded[1]["kid"], jwk.export[:kid]
113
+
114
+ assert is_uuid?(decoded[0]["x-roku-request-key"])
115
+ spec = decoded[0]["x-roku-request-spec"]
116
+ refute_nil spec
117
+ assert_equal spec["serviceUrn"], urn
118
+ assert_equal spec["httpMethod"], method
119
+ assert_equal spec["path"], path
120
+ assert_equal spec["bodySha256Base64"], sha256
121
+ end
122
+
123
+ def test_api_get
124
+ api = RokuAPI.new(config: @config)
125
+ path = "/test/path"
126
+ api.instance_variable_set(:@api_key, "key1")
127
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
128
+ response = api.send(:api_get, path)
129
+ assert_requested(:get, "https://apipub.roku.com/developer/v1/test/path", headers: {
130
+ "Accept" => "application/json",
131
+ "Content-Type" => "application/json",
132
+ "Authorization" => /Bearer .*/
133
+ })
134
+ end
135
+
136
+ def test_api_post
137
+ api = RokuAPI.new(config: @config)
138
+ path = "/test/path"
139
+ token_path = "/other/path"
140
+ api.instance_variable_set(:@api_key, "key1")
141
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
142
+ encoded = Base64.encode64(package.read)
143
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
144
+ called = false
145
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
146
+ called = true
147
+ assert_equal path, token_path
148
+ "token"
149
+ end
150
+ params = {"status" => "Published"}
151
+ api.stub(:get_jwt_token, jwt_proc) do
152
+ response = api.send(:api_post, path, token_path, package, params)
153
+ end
154
+ assert called
155
+ assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
156
+ body: {"appFileBase64Encoded" => encoded}.to_json,
157
+ headers: {
158
+ "Accept" => "application/json",
159
+ "Content-Type" => "application/json",
160
+ "Authorization" => /Bearer token/
161
+ },
162
+ query: {"status" => "Published"}
163
+ )
164
+ end
165
+
166
+ def test_api_post_no_package
167
+ api = RokuAPI.new(config: @config)
168
+ path = "/test/path"
169
+ token_path = "/other/path"
170
+ api.instance_variable_set(:@api_key, "key1")
171
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
172
+ called = false
173
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
174
+ called = true
175
+ assert_equal path, token_path
176
+ "token"
177
+ end
178
+ api.stub(:get_jwt_token, jwt_proc) do
179
+ response = api.send(:api_post, path, token_path)
180
+ end
181
+ assert called
182
+ assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
183
+ headers: {
184
+ "Accept" => "application/json",
185
+ "Content-Type" => "application/json",
186
+ "Authorization" => /Bearer .*/
187
+ }
188
+ )
189
+ end
190
+
191
+ def test_api_patch
192
+ api = RokuAPI.new(config: @config)
193
+ path = "/test/path"
194
+ token_path = "/other/path"
195
+ api.instance_variable_set(:@api_key, "key1")
196
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
197
+ encoded = Base64.encode64(package.read)
198
+ @requests.push(stub_request(:any, /apipub.roku.com.*/))
199
+ called = false
200
+ jwt_proc = proc do |api_key, service_urn, method, path, body|
201
+ called = true
202
+ assert_equal path, token_path
203
+ "token"
204
+ end
205
+ api.stub(:get_jwt_token, jwt_proc) do
206
+ response = api.send(:api_patch, path, token_path, package)
207
+ end
208
+ assert called
209
+ assert_requested(:patch, "https://apipub.roku.com/developer/v1/test/path",
210
+ body: {"path" => "/appFileBase64Encoded", "value" => encoded, "op" => "replace"}.to_json,
211
+ headers: {
212
+ "Accept" => "application/json",
213
+ "Content-Type" => "application/json",
214
+ "Authorization" => /Bearer token/
215
+ }
216
+ )
217
+ end
218
+
219
+ def test_get_channel_versions
220
+ api = RokuAPI.new(config: @config)
221
+ channel = "1234"
222
+ api.instance_variable_set(:@api_key, "key1")
223
+ response = Minitest::Mock.new
224
+ body = { "id" => "1234", "version" => "1.1"}
225
+ response.expect(:body, body.to_json)
226
+ called = 0
227
+ get_proc = proc do |path|
228
+ called +=1
229
+ assert_equal path, "/external/channels/#{channel}/versions"
230
+ response
231
+ end
232
+ sort_proc = proc do |versions|
233
+ called += 1
234
+ versions
235
+ end
236
+ api.stub(:api_get, get_proc) do
237
+ api.stub(:sorted_versions, sort_proc) do
238
+ result = api.send(:get_channel_versions, channel)
239
+ assert_equal result, body
240
+ end
241
+ end
242
+ assert_equal 2, called
243
+ end
244
+
245
+ def test_submit_no_channel_id
246
+ api = RokuAPI.new(config: @config)
247
+ assert_raises RokuBuilder::InvalidOptions do
248
+ api.submit(options: {})
249
+ end
250
+ end
251
+
252
+ def test_submit_without_unpublished
253
+ api = RokuAPI.new(config: @config)
254
+ called = {}
255
+ @options[:no_publish] = true
256
+ response = Minitest::Mock.new
257
+ response.expect(:success?, true)
258
+ response.expect(:body, api_versions[0].to_json)
259
+ updated = proc {called[:updated] = true; response}
260
+ created = proc {called[:created] = true; response}
261
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
262
+ body: api_versions.to_json
263
+ ))
264
+ api.stub(:create_channel_version, created) do
265
+ api.stub(:update_channel_version, updated) do
266
+ api.stub(:get_package, "") do
267
+ api.submit(options: @options)
268
+ end
269
+ end
270
+ end
271
+ assert called[:created]
272
+ assert_nil called[:updated]
273
+ assert api.instance_variable_get(:@no_publish)
274
+
275
+ end
276
+ def test_submit_without_latest_unpublished
277
+ api = RokuAPI.new(config: @config)
278
+ called = {}
279
+ body = api_versions
280
+ body.push(api_versions.first)
281
+ body[1]["version"] = "1.3"
282
+ body[1]["channelState"] = "Unpublished"
283
+ response = Minitest::Mock.new
284
+ response.expect(:success?, true)
285
+ response.expect(:body, body[0].to_json)
286
+ updated = proc {called[:updated] = true; response}
287
+ created = proc {called[:created] = true; response}
288
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
289
+ body: body.to_json
290
+ ))
291
+ api.stub(:create_channel_version, created) do
292
+ api.stub(:update_channel_version, updated) do
293
+ api.stub(:get_package, "") do
294
+ api.submit(options: @options)
295
+ end
296
+ end
297
+ end
298
+ assert called[:created]
299
+ assert_nil called[:updated]
300
+ end
301
+
302
+ def test_submit_with_unpublished
303
+ api = RokuAPI.new(config: @config)
304
+ body = api_versions
305
+ body[0]["channelState"] = "Unpublished"
306
+ called = {}
307
+ response = Minitest::Mock.new
308
+ response.expect(:success?, true)
309
+ response.expect(:body, body[0].to_json)
310
+ updated = proc do |channel, package, version|
311
+ called[:updated] = true
312
+ assert_equal body[0]["id"], version
313
+ response
314
+ end
315
+ created = proc {called[:created] = true; response}
316
+ @requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
317
+ body: body.to_json
318
+ ))
319
+ api.stub(:create_channel_version, created) do
320
+ api.stub(:update_channel_version, updated) do
321
+ api.stub(:get_package, "") do
322
+ api.submit(options: @options)
323
+ end
324
+ end
325
+ end
326
+ assert called[:updated]
327
+ assert_nil called[:created]
328
+ end
329
+
330
+ def test_create_channel_version
331
+ api = RokuAPI.new(config: @config)
332
+ channel = "1234"
333
+ api.instance_variable_set(:@api_key, "key1")
334
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
335
+ called = false
336
+ post_proc = proc do |path, token_path, package, params|
337
+ called = true
338
+ assert_equal path, "/external/channels/#{channel}/versions"
339
+ assert_equal token_path, "/external/channels/#{channel}/versions"
340
+ assert_equal "Published", params["channelState"]
341
+ assert_kind_of File, package
342
+ end
343
+ api.stub(:api_post, post_proc) do
344
+ api.send(:create_channel_version, channel, package)
345
+ end
346
+ assert called
347
+ end
348
+
349
+ def test_create_channel_version_no_publish
350
+ api = RokuAPI.new(config: @config)
351
+ channel = "1234"
352
+ api.instance_variable_set(:@api_key, "key1")
353
+ api.instance_variable_set(:@no_publish, true)
354
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
355
+ called = false
356
+ post_proc = proc do |path, token_path, package, params|
357
+ called = true
358
+ assert_equal path, "/external/channels/#{channel}/versions"
359
+ assert_equal token_path, "/external/channels/#{channel}/versions"
360
+ assert_nil params
361
+ assert_kind_of File, package
362
+ end
363
+ api.stub(:api_post, post_proc) do
364
+ api.send(:create_channel_version, channel, package)
365
+ end
366
+ assert called
367
+ end
368
+
369
+ def test_update_channel_version
370
+ api = RokuAPI.new(config: @config)
371
+ channel = "1234"
372
+ version = "1234"
373
+ api.instance_variable_set(:@api_key, "key1")
374
+ package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
375
+ called = false
376
+ patch_proc = proc do |path, token_path, package|
377
+ called = true
378
+ assert_equal path, "/external/channel/#{channel}/#{version}"
379
+ assert_equal token_path, "/external/channels/#{channel}/#{version}"
380
+ assert_kind_of File, package
381
+ end
382
+ api.stub(:api_patch, patch_proc) do
383
+ api.send(:update_channel_version, channel, package, version)
384
+ end
385
+ assert called
386
+ end
387
+
388
+ def test_publish_no_channel_id
389
+ api = RokuAPI.new(config: @config)
390
+ assert_raises RokuBuilder::InvalidOptions do
391
+ params = {options: {}}
392
+ api.send(:publish, **params)
393
+ end
394
+ end
395
+
396
+ def test_publish_without_unpublished
397
+ api = RokuAPI.new(config: @config)
398
+ expected_channel = "1234"
399
+ api.instance_variable_set(:@api_key, "key1")
400
+ body = api_versions
401
+ called = false
402
+ get_proc = proc do |channel|
403
+ called = true
404
+ assert_equal expected_channel, channel
405
+ body
406
+ end
407
+ api.stub(:get_channel_versions, get_proc) do
408
+ assert_raises RokuBuilder::ExecutionError do
409
+ params = {options: {channel_id: expected_channel}}
410
+ api.send(:publish, **params)
411
+ end
412
+ end
413
+ assert called
414
+ end
415
+
416
+ def test_publish_without_latest_unpublished
417
+ api = RokuAPI.new(config: @config)
418
+ expected_channel = "1234"
419
+ api.instance_variable_set(:@api_key, "key1")
420
+ body = api_versions
421
+ body.push(api_versions.first)
422
+ body[1]["version"] = "1.3"
423
+ body[1]["channelState"] = "Unpublished"
424
+ called = false
425
+ get_proc = proc do |channel|
426
+ called = true
427
+ assert_equal expected_channel, channel
428
+ body
429
+ end
430
+ api.stub(:get_channel_versions, get_proc) do
431
+ assert_raises RokuBuilder::ExecutionError do
432
+ params = {options: {channel_id: expected_channel}}
433
+ api.send(:publish, **params)
434
+ end
435
+ end
436
+ assert called
437
+ end
438
+
439
+ def test_publish_with_unpublished
440
+ api = RokuAPI.new(config: @config)
441
+ expected_channel = "1234"
442
+ api.instance_variable_set(:@api_key, "key1")
443
+ body = [{ "id" => "1234", "version" => "1.1", "channelState" => "Unpublished"}]
444
+ called = 0
445
+ get_proc = proc do |channel|
446
+ called += 1
447
+ assert_equal expected_channel, channel
448
+ body
449
+ end
450
+ response = Minitest::Mock.new
451
+ response.expect(:success?, true)
452
+ response.expect(:body, body[0].to_json)
453
+ post_proc = proc do |channel, version|
454
+ called += 1
455
+ assert_equal expected_channel, channel
456
+ assert_equal body.first["id"], version
457
+ response
458
+ end
459
+ api.stub(:get_channel_versions, get_proc) do
460
+ api.stub(:publish_channel_version, post_proc) do
461
+ params = {options: {channel_id: expected_channel}}
462
+ api.send(:publish, **params)
463
+ end
464
+ end
465
+ assert_equal called, 2
466
+ end
467
+
468
+ def test_publish_channel_version
469
+ api = RokuAPI.new(config: @config)
470
+ channel = "1234"
471
+ api.instance_variable_set(:@api_key, "key1")
472
+ response = Minitest::Mock.new
473
+ body = { "id" => "1234", "version" => "1.1"}
474
+ response.expect(:body, body.to_json)
475
+ called = false
476
+ post_proc = proc do |path, token_path|
477
+ called = true
478
+ assert_equal path, "/external/channels/#{channel}/versions/#{body["id"]}"
479
+ assert_equal token_path, "/external/channels/#{channel}/versions/#{body["id"]}/state"
480
+ end
481
+ api.stub(:api_post, post_proc) do
482
+ api.send(:publish_channel_version, channel, body["id"])
483
+ end
484
+ assert called
485
+ end
486
+
487
+ def test_submit_failure_create
488
+ api = RokuAPI.new(config: @config)
489
+ response = Minitest::Mock.new
490
+ response.expect(:success?, false)
491
+ response.expect(:reason_phrase, "reason")
492
+ api.stub(:get_channel_versions, api_versions) do
493
+ api.stub(:create_channel_version, response) do
494
+ api.stub(:get_package, "") do
495
+ assert_raises RokuBuilder::ExecutionError do
496
+ api.submit(options: @options)
497
+ end
498
+ end
499
+ end
500
+ end
501
+ assert_mock response
502
+ end
503
+
504
+ def test_submit_response_created
505
+ api = RokuAPI.new(config: @config)
506
+ body = { "id" => "1234", "version" => "1.1"}
507
+ response = Minitest::Mock.new
508
+ response.expect(:success?, true)
509
+ response.expect(:body, body.to_json)
510
+ api.stub(:get_channel_versions, api_versions) do
511
+ api.stub(:create_channel_version, response) do
512
+ api.stub(:get_package, "") do
513
+ response_json = api.submit(options: @options)
514
+ assert_equal body, response_json
515
+ end
516
+ end
517
+ end
518
+ assert_mock response
519
+ end
520
+
521
+ def test_submit_response_updated
522
+ api = RokuAPI.new(config: @config)
523
+ body = { "id" => "1234", "version" => "1.1"}
524
+ response = Minitest::Mock.new
525
+ response.expect(:success?, true)
526
+ response.expect(:body, body.to_json)
527
+ versions = api_versions
528
+ versions[0]["channelState"] = "Unpublished"
529
+ api.stub(:get_channel_versions, versions) do
530
+ api.stub(:update_channel_version, response) do
531
+ api.stub(:get_package, "") do
532
+ response_json = api.submit(options: @options)
533
+ assert_equal body, response_json
534
+ end
535
+ end
536
+ end
537
+ assert_mock response
538
+ end
539
+
540
+ def test_publish_response
541
+ api = RokuAPI.new(config: @config)
542
+ body = { "id" => "1234", "version" => "1.1"}
543
+ response = Minitest::Mock.new
544
+ response.expect(:success?, true)
545
+ response.expect(:body, body.to_json)
546
+ versions = api_versions
547
+ versions[0]["channelState"] = "Unpublished"
548
+ api.stub(:get_channel_versions, versions) do
549
+ api.stub(:publish_channel_version, response) do
550
+ response_json = api.publish(options: @options)
551
+ assert_equal body, response_json
552
+ end
553
+ end
554
+ assert_mock response
555
+ end
556
+ end
557
+ 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,79 @@ 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
+ }
148
+ ]
149
+ 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.27.2
4
+ version: 4.29.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - greeneca
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-13 00:00:00.000000000 Z
11
+ date: 2024-01-25 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