roku_builder 4.27.2 → 4.29.1

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: 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