faastruby 0.4.12 → 0.4.14

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.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +15 -4
  4. data/Gemfile.lock +2 -2
  5. data/README.md +2 -0
  6. data/exe/faastruby-server +4 -2
  7. data/lib/faastruby/cli/commands/function/build.rb +20 -1
  8. data/lib/faastruby/cli/commands/function/deploy_to.rb +20 -1
  9. data/lib/faastruby/cli/commands/function/new.rb +6 -4
  10. data/lib/faastruby/cli/commands/function/update_context.rb +2 -2
  11. data/lib/faastruby/server.rb +10 -233
  12. data/lib/faastruby/server/concurrency_controller.rb +51 -0
  13. data/lib/faastruby/server/errors.rb +3 -0
  14. data/lib/faastruby/server/event.rb +19 -0
  15. data/lib/faastruby/server/event_channel.rb +19 -0
  16. data/lib/faastruby/server/event_hub.rb +50 -0
  17. data/lib/faastruby/server/function_object.rb +9 -0
  18. data/lib/faastruby/server/response.rb +25 -0
  19. data/lib/faastruby/server/runner.rb +43 -0
  20. data/lib/faastruby/server/runner_methods.rb +106 -0
  21. data/lib/faastruby/server/subscriber.rb +16 -0
  22. data/lib/faastruby/spec_helper.rb +36 -0
  23. data/lib/faastruby/version.rb +1 -1
  24. data/templates/crystal/example-blank/spec/spec_helper.cr +1 -1
  25. data/templates/crystal/example/spec/spec_helper.cr +1 -1
  26. data/templates/ruby/example-blank/Gemfile +1 -0
  27. data/templates/ruby/example-blank/spec/handler_spec.rb +6 -1
  28. data/templates/ruby/example-blank/spec/spec_helper.rb +2 -2
  29. data/templates/ruby/example/Gemfile +1 -0
  30. data/templates/ruby/example/spec/handler_spec.rb +8 -3
  31. data/templates/ruby/example/spec/spec_helper.rb +2 -2
  32. metadata +13 -6
  33. data/templates/crystal/example-blank/spec/helpers/faastruby.cr +0 -77
  34. data/templates/crystal/example/spec/helpers/faastruby.cr +0 -77
  35. data/templates/ruby/example-blank/spec/helpers/faastruby.rb +0 -66
  36. data/templates/ruby/example/spec/helpers/faastruby.rb +0 -65
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6368a1d3dad4d02f5e3a24262adaff96cdc7767bbf825691d4e49d65fbcea21b
4
- data.tar.gz: 02e19e2cb7afb3c0bd3b91ba885a6fae26995ad15445b3e015224bc6344d7e21
3
+ metadata.gz: f33bd1f4ef4018f6d54b1a7f3ea894cd85d0484b2eb9f340f5997c0986b79499
4
+ data.tar.gz: e368bf8bb7eae9eee54270f8cf350bc605b1e8b3c8c20f346f1ff9cdd9fc335c
5
5
  SHA512:
6
- metadata.gz: 2df07aeae193658b8d1466a84dfb571452e136c706ec0edade1ac8278b9868b9ea41eb60c2bf10266c46eb67196a981005e25d3dda6d9e9570e76b714c38a52f
7
- data.tar.gz: dadf343fa1946f4750903c37626d81bae076a25098551574a9138327139a814f56a12372432b152c2b92c1133bd5384138c4fb915102bd2ce14c6bd4a90ba6d7
6
+ metadata.gz: ff4b5f5104900ed7001cea0c79a48a00c943a325ea4c34e5bb54b34f1f775bea42bb0fee87e05faeeba130101c2aa1227858ac95c438a514c6e3c4c2d195bcb9
7
+ data.tar.gz: f24468bc7302059f788d6133dbbf2f39a2b68686e14b0b29711ad8b26143e58d3c1f37af968f397a9335adec42343189341aa624c4e57a6a1a1460faf303f386
data/.gitignore CHANGED
@@ -7,3 +7,4 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  /*.gem
10
+ /archive
data/CHANGELOG.md CHANGED
@@ -1,10 +1,21 @@
1
1
  # Changelog
2
2
 
3
- ## 0.4.12 - Jan 26 2019
4
- Special thanks to @HellRok for fixing those bugs!
3
+ ## 0.4.14 - Feb 1 2019
4
+ - Ruby functions now use a spec helper from `faastruby` gem.
5
+ - Crystal functions now use the shard `faastruby-spec-helper` to assist on tests.
6
+ - Mock `publish` method on tests.
7
+ - Wrap functions in anonymous module to avoid concurrency problems.
8
+ - Read all STDIN when updating context with --stdin [PR-5](https://github.com/FaaStRuby/faastruby-cli/pull/5) | Thanks [Justin](https://github.com/presidentbeef)!
9
+ - `shards install` runs when building crystal function before deploy
10
+ - Better message when updating the function context
11
+ - Fixed output when creating a function with `faastruby new`
12
+
13
+ A new version of the platform API was released in tandem to address the issue that would erase contexts when a function is redeployed. Thanks [Justin](https://github.com/presidentbeef) again for pointing that out.
5
14
 
6
- - FaaStRuby Server: Respond with css content type (#4)
7
- - Setup the server to respond to HEAD requests (#3)
15
+ ## 0.4.12 - Jan 26 2019
16
+ Special thanks to [Sean Earle](https://github.com/HellRok) for fixing those bugs!
17
+ - FaaStRuby Server: Respond with css content type [PR-4](https://github.com/FaaStRuby/faastruby-cli/pull/4)
18
+ - Setup the server to respond to HEAD requests [PR-3](https://github.com/FaaStRuby/faastruby-cli/pull/3)
8
19
 
9
20
  ## 0.4.11 - Jan 19 2019
10
21
  - Fix wrong working directory when running functions locally with `faastruby server`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- faastruby (0.4.11)
4
+ faastruby (0.4.13)
5
5
  colorize (~> 0.8)
6
6
  faastruby-rpc (~> 0.2.1)
7
7
  oj (~> 3.6)
@@ -38,7 +38,7 @@ GEM
38
38
  mustermann (1.0.3)
39
39
  necromancer (0.4.0)
40
40
  netrc (0.11.0)
41
- oj (3.7.7)
41
+ oj (3.7.8)
42
42
  pastel (0.7.2)
43
43
  equatable (~> 0.5.0)
44
44
  tty-color (~> 0.4.0)
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/faastruby.svg)](https://badge.fury.io/rb/faastruby)
2
2
  [![Build Status](https://travis-ci.org/FaaStRuby/faastruby-cli.svg?branch=master)](https://travis-ci.org/FaaStRuby/faastruby-cli)
3
3
 
4
+ [Changelog](https://github.com/FaaStRuby/faastruby-cli/blob/master/CHANGELOG.md)
5
+
4
6
  # faastruby-cli
5
7
 
6
8
  CLI tool for managing workspaces and functions hosted at [FaaStRuby](https://faastruby.io).
data/exe/faastruby-server CHANGED
@@ -7,6 +7,7 @@ require 'faastruby/server'
7
7
  require 'sinatra'
8
8
  require 'sinatra/multi_route'
9
9
  require 'colorize'
10
+
10
11
  FaaStRuby::EventHub.listen_for_events!
11
12
 
12
13
  set :port, 3000
@@ -22,6 +23,7 @@ set :show_exceptions, true
22
23
  set :run, true
23
24
 
24
25
  register Sinatra::MultiRoute
26
+
25
27
  route :head, :get, :post, :put, :patch, :delete, '/:workspace_name/:function_name' do
26
28
  path = "#{params[:workspace_name]}/#{params[:function_name]}"
27
29
  headers = env.select { |key, value| key.include?('HTTP_') || ['CONTENT_TYPE', 'CONTENT_LENGTH', 'REMOTE_ADDR', 'REQUEST_METHOD', 'QUERY_STRING'].include?(key) }
@@ -34,7 +36,7 @@ route :head, :get, :post, :put, :patch, :delete, '/:workspace_name/:function_nam
34
36
  end
35
37
  query_params = parse_query(request.query_string)
36
38
  context = set_context(params[:workspace_name], params[:function_name])
37
- event = FaaStRuby::Event.new(body, query_params, headers, context)
39
+ event = FaaStRuby::Event.new(body: body, query_params: query_params, headers: headers, context: context)
38
40
  response = FaaStRuby::Runner.new.call(params[:workspace_name], params[:function_name], event, rpc_args)
39
41
  status response.status
40
42
  headers response.headers
@@ -44,7 +46,7 @@ route :head, :get, :post, :put, :patch, :delete, '/:workspace_name/:function_nam
44
46
  response_body = response.body
45
47
  end
46
48
  puts "[#{path}] #=> status=#{response.status} body=#{response_body.inspect} headers=#{Oj.dump response.headers}".light_blue
47
- body response_body
49
+ body response_body
48
50
  end
49
51
 
50
52
  def parse_body(body, content_type, method)
@@ -20,8 +20,21 @@ module FaaStRuby
20
20
  @options['output_file'] ||= "#{@function_name}.zip"
21
21
  end
22
22
 
23
+ def ruby_runtime?
24
+ @yaml_config['runtime'].nil? || @yaml_config['runtime'].match(/^ruby/)
25
+ end
26
+
27
+ def crystal_runtime?
28
+ @yaml_config['runtime'].match(/^crystal/)
29
+ end
30
+
23
31
  def run
24
- FaaStRuby::CLI.error('Please fix the problems above and try again') unless bundle_install
32
+ if ruby_runtime?
33
+ FaaStRuby::CLI.error('Please fix the problems above and try again') unless bundle_install
34
+ end
35
+ if crystal_runtime?
36
+ FaaStRuby::CLI.error('Please fix the problems above and try again') unless shards_install
37
+ end
25
38
  tests_passed = run_tests
26
39
  FaaStRuby::CLI.error("Build aborted because tests failed and you have 'abort_build_when_tests_fail: true' in 'faastruby.yml'") unless tests_passed || !@abort_when_tests_fail
27
40
  puts "Warning: Ignoring failed tests because you have 'abort_build_when_tests_fail: false' in 'faastruby.yml'".yellow if !tests_passed && !@abort_when_tests_fail
@@ -42,6 +55,12 @@ module FaaStRuby
42
55
  self.class.build(source, output_file)
43
56
  end
44
57
 
58
+ def shards_install
59
+ puts '[build] Verifying dependencies'
60
+ return true unless File.file?('shard.yml')
61
+ system('shards check') || system('shards install')
62
+ end
63
+
45
64
  def bundle_install
46
65
  puts '[build] Verifying dependencies'
47
66
  return true unless File.file?('Gemfile')
@@ -13,9 +13,22 @@ module FaaStRuby
13
13
  load_credentials(exit_on_error: false)
14
14
  end
15
15
 
16
+ def ruby_runtime?
17
+ @yaml_config['runtime'].nil? || @yaml_config['runtime'].match(/^ruby/)
18
+ end
19
+
20
+ def crystal_runtime?
21
+ @yaml_config['runtime'].match(/^crystal/)
22
+ end
23
+
16
24
  def run
17
25
  create_or_use_workspace
18
- FaaStRuby::CLI.error('Please fix the problems above and try again') unless bundle_install
26
+ if ruby_runtime?
27
+ FaaStRuby::CLI.error('Please fix the problems above and try again') unless bundle_install
28
+ end
29
+ if crystal_runtime?
30
+ FaaStRuby::CLI.error('Please fix the problems above and try again') unless shards_install
31
+ end
19
32
  tests_passed = run_tests
20
33
  FaaStRuby::CLI.error("Deploy aborted because tests failed and you have 'abort_deploy_when_tests_fail: true' in 'faastruby.yml'") unless tests_passed || !@abort_when_tests_fail
21
34
  puts "Warning: Ignoring failed tests because you have 'abort_deploy_when_tests_fail: false' in 'faastruby.yml'".yellow if !tests_passed && !@abort_when_tests_fail
@@ -59,6 +72,12 @@ module FaaStRuby
59
72
  end
60
73
  end
61
74
 
75
+ def shards_install
76
+ puts '[build] Verifying dependencies'
77
+ return true unless File.file?('shard.yml')
78
+ system('shards check') || system('shards install')
79
+ end
80
+
62
81
  def bundle_install
63
82
  puts '[build] Verifying dependencies'
64
83
  return true unless File.file?('Gemfile')
@@ -82,8 +82,6 @@ EOS
82
82
  when 'ruby'
83
83
  puts "+ d #{@base_dir}".green
84
84
  puts "+ d #{@base_dir}/spec".green
85
- puts "+ d #{@base_dir}/spec/helpers".green
86
- puts "+ f #{@base_dir}/spec/helpers/faastruby.rb".green
87
85
  puts "+ f #{@base_dir}/spec/handler_spec.rb".green
88
86
  puts "+ f #{@base_dir}/spec/spec_helper.rb".green
89
87
  puts "+ f #{@base_dir}/Gemfile".green
@@ -91,8 +89,6 @@ EOS
91
89
  when 'crystal'
92
90
  puts "+ d #{@base_dir}".green
93
91
  puts "+ d #{@base_dir}/spec".green
94
- puts "+ d #{@base_dir}/spec/helpers".green
95
- puts "+ f #{@base_dir}/spec/helpers/faastruby.cr".green
96
92
  puts "+ f #{@base_dir}/spec/handler_spec.cr".green
97
93
  puts "+ f #{@base_dir}/spec/spec_helper.cr".green
98
94
  puts "+ d #{@base_dir}/src".green
@@ -149,6 +145,12 @@ EOS
149
145
  @function_name => {
150
146
  'main' => 'src/handler.cr'
151
147
  }
148
+ },
149
+ 'development_dependencies' => {
150
+ 'faastruby-spec-helper' => {
151
+ 'github' => 'faastruby/faastruby-spec-helper.cr',
152
+ 'version' => '~> 0.1.0'
153
+ }
152
154
  }
153
155
  }.to_yaml
154
156
  write_file("#{@base_dir}/shard.yml", shards)
@@ -14,7 +14,7 @@ module FaaStRuby
14
14
  end
15
15
 
16
16
  def run
17
- spinner = spin("Uploading context data to '#{@workspace_name}'...")
17
+ spinner = spin("Uploading context data for function '#{@function_name}' to workspace '#{@workspace_name}'...")
18
18
  workspace = FaaStRuby::Workspace.new(name: @workspace_name)
19
19
  function = FaaStRuby::Function.new(name: @function_name, workspace: workspace)
20
20
  function.update(new_context: @options['data'])
@@ -52,7 +52,7 @@ module FaaStRuby
52
52
  when '-d', '--data'
53
53
  @options['data'] = @args.shift
54
54
  when '--stdin'
55
- @options['data'] = STDIN.gets.chomp
55
+ @options['data'] = STDIN.read
56
56
  else
57
57
  FaaStRuby::CLI.error("Unknown argument: #{option}")
58
58
  end
@@ -1,236 +1,13 @@
1
1
  module FaaStRuby
2
2
  PROJECT_ROOT = Dir.pwd
3
- class DoubleRenderError < StandardError; end
4
- class EventChannel
5
- @@channels = {}
6
- def self.channels
7
- @@channels
8
- end
9
- attr_accessor :name
10
- def initialize(channel)
11
- @name = channel
12
- @@channels[channel] ||= []
13
- end
14
- def subscribe(function_path)
15
- @@channels[@name] << function_path
16
- end
17
- def subscribers
18
- @@channels[@name] || []
19
- end
20
- end
21
- class Subscriber
22
- attr_accessor :path
23
- def initialize(path)
24
- @path = path
25
- @workspace_name, @function_name = @path.split("/")
26
- end
27
-
28
- def call(encoded_data)
29
- data = Base64.urlsafe_decode64(encoded_data)
30
- headers = {'X-Origin' => 'event_hub', 'Content-Transfer-Encoding' => 'base64'}
31
- event = Event.new(data, {}, headers, nil)
32
- Runner.new.call(@workspace_name, @function_name, event, [])
33
- end
34
- end
35
-
36
- class EventHub
37
- @@queue = Queue.new
38
- def self.queue
39
- @@queue
40
- end
41
-
42
- def self.push(payload)
43
- @@queue << payload
44
- end
45
-
46
- def self.thread
47
- @@thread
48
- end
49
-
50
- def self.load_subscribers
51
- Dir.glob('*/*/faastruby.yml').each do |file|
52
- workspace_name, function_name, _ = file.split('/')
53
- path = "#{workspace_name}/#{function_name}"
54
- config = YAML.load(File.read(file))
55
- next unless config['channels'].is_a?(Array)
56
- config['channels'].compact!
57
- config['channels'].each do |c|
58
- channel = EventChannel.new(c)
59
- channel.subscribe(path)
60
- end
61
- end
62
- puts "[EventHub] Channel subscriptions: #{EventChannel.channels}".yellow
63
- puts "[EventHub] If you modify 'faastruby.yml' in any function, you will need to restart the server to apply the changes.".yellow
64
- end
65
-
66
- def self.listen_for_events!
67
- load_subscribers
68
- @@thread = Thread.new do
69
- loop do
70
- encoded_channel, encoded_data = @@queue.pop.split(',')
71
- channel = EventChannel.new(Base64.urlsafe_decode64(encoded_channel))
72
- puts "[EventHub] Event channel=#{channel.name.inspect}".yellow
73
- channel.subscribers.each do |s|
74
- subscriber = Subscriber.new(s)
75
- puts "[EventHub] Trigger function=#{subscriber.path.inspect} base64_payload=#{encoded_data.inspect}".yellow
76
- response = subscriber.call(encoded_data)
77
- puts "[#{subscriber.path}] #=> status=#{response.status} body=#{response.body.inspect} headers=#{Oj.dump response.headers}".light_blue
78
- end
79
- end
80
- end
81
- puts "[EventHub] Events thread started.".yellow
82
- end
83
- end
84
-
85
- class Runner
86
- def initialize
87
- @rendered = false
88
- end
89
-
90
- def path
91
- @path
92
- end
93
-
94
- def call(workspace_name, function_name, event, args)
95
- @path = "#{FaaStRuby::PROJECT_ROOT}/#{workspace_name}/#{function_name}"
96
- begin
97
- load "#{@path}/handler.rb"
98
- Dir.chdir(@path)
99
- response = handler(event, *args)
100
- return response if response.is_a?(FaaStRuby::Response)
101
- body = {
102
- 'error' => "Please use the helpers 'render' or 'respond_with' as your function return value."
103
- }
104
- FaaStRuby::Response.new(body: Oj.dump(body), status: 500, headers: {'Content-Type' => 'application/json'})
105
- rescue Exception => e
106
- body = {
107
- 'error' => e.message,
108
- 'location' => e.backtrace&.first,
109
- }
110
- FaaStRuby::Response.new(body: Oj.dump(body), status: 500, headers: {'Content-Type' => 'application/json'})
111
- end
112
- end
113
-
114
- def rendered!
115
- @rendered = true
116
- end
117
- def rendered?
118
- @rendered
119
- end
120
-
121
- def respond_with(body, status: 200, headers: {}, binary: false)
122
- raise FaaStRuby::DoubleRenderError.new("You called 'render' or 'respond_with' twice in your handler method") if rendered?
123
- response = FaaStRuby::Response.new(body: body, status: status, headers: headers, binary: binary)
124
- rendered!
125
- response
126
- end
127
-
128
- def render(
129
- js: nil,
130
- css: nil,
131
- body: nil,
132
- inline: nil,
133
- html: nil,
134
- json: nil,
135
- yaml: nil,
136
- text: nil,
137
- data: nil,
138
- png: nil,
139
- svg: nil,
140
- jpeg: nil,
141
- gif: nil,
142
- icon: nil,
143
- status: 200, headers: {}, content_type: nil, binary: false
144
- )
145
- headers["Content-Type"] = content_type if content_type
146
- bin = false
147
- case
148
- when json
149
- headers["Content-Type"] ||= "application/json"
150
- resp_body = json.is_a?(String) ? json : Oj.dump(json)
151
- when html, inline
152
- headers["Content-Type"] ||= "text/html"
153
- resp_body = html
154
- when text
155
- headers["Content-Type"] ||= "text/plain"
156
- resp_body = text
157
- when yaml
158
- headers["Content-Type"] ||= "application/yaml"
159
- resp_body = yaml.is_a?(String) ? yaml : YAML.load(yaml)
160
- when body
161
- headers["Content-Type"] ||= "application/octet-stream"
162
- bin = binary
163
- resp_body = bin ? Base64.urlsafe_encode64(body) : body
164
- when data
165
- headers["Content-Type"] ||= "application/octet-stream"
166
- resp_body = Base64.urlsafe_encode64(data)
167
- bin = true
168
- when js
169
- headers["Content-Type"] ||= "text/javascript"
170
- resp_body = js
171
- when css
172
- headers["Content-Type"] ||= "text/css"
173
- resp_body = css
174
- when png
175
- headers["Content-Type"] ||= "image/png"
176
- resp_body = Base64.urlsafe_encode64(png)
177
- bin = true
178
- when svg
179
- headers["Content-Type"] ||= "image/svg+xml"
180
- resp_body = svg
181
- when jpeg
182
- headers["Content-Type"] ||= "image/jpeg"
183
- resp_body = Base64.urlsafe_encode64(jpeg)
184
- bin = true
185
- when gif
186
- headers["Content-Type"] ||= "image/gif"
187
- resp_body = Base64.urlsafe_encode64(gif)
188
- bin = true
189
- when icon
190
- headers["Content-Type"] ||= "image/x-icon"
191
- resp_body = Base64.urlsafe_encode64(icon)
192
- bin = true
193
- end
194
- respond_with(resp_body, status: status, headers: headers, binary: bin)
195
- end
196
-
197
- def puts(msg)
198
- super "[#{@path}] #{msg}".green
199
- end
200
-
201
- def publish(channel, data: nil)
202
- begin
203
- encoded_data = data ? Base64.urlsafe_encode64(data, padding: false) : ""
204
- payload = %(#{Base64.urlsafe_encode64(channel, padding: false)},#{encoded_data})
205
- EventHub.queue.push payload
206
- true
207
- rescue
208
- false
209
- end
210
- end
211
- end
212
-
213
- class Event
214
- attr_accessor :body, :query_params, :headers, :context
215
- def initialize(body, query_params, headers, context)
216
- @body = body
217
- @query_params = query_params
218
- @headers = headers
219
- @context = context
220
- end
221
- end
222
-
223
- class Response
224
- attr_accessor :body, :status, :headers, :binary
225
- def initialize(body:, status: 200, headers: {}, binary: false)
226
- @body = body
227
- @status = status
228
- @headers = headers
229
- @binary = binary
230
- end
231
-
232
- def binary?
233
- @binary
234
- end
235
- end
3
+ require 'faastruby/server/concurrency_controller'
4
+ require 'faastruby/server/errors'
5
+ require 'faastruby/server/event_channel'
6
+ require 'faastruby/server/subscriber'
7
+ require 'faastruby/server/event_hub'
8
+ require 'faastruby/server/runner_methods'
9
+ require 'faastruby/server/function_object'
10
+ require 'faastruby/server/runner'
11
+ require 'faastruby/server/event'
12
+ require 'faastruby/server/response'
236
13
  end