faastruby 0.4.18 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -3
- data/Gemfile.lock +28 -4
- data/README.md +63 -5
- data/faastruby.gemspec +5 -1
- data/lib/faastruby.rb +1 -0
- data/lib/faastruby/api.rb +154 -6
- data/lib/faastruby/base.rb +3 -9
- data/lib/faastruby/cli.rb +39 -12
- data/lib/faastruby/cli/base_command.rb +66 -0
- data/lib/faastruby/cli/commands.rb +122 -59
- data/lib/faastruby/cli/commands/account/base_command.rb +10 -0
- data/lib/faastruby/cli/commands/account/confirm.rb +94 -0
- data/lib/faastruby/cli/commands/account/login.rb +86 -0
- data/lib/faastruby/cli/commands/account/logout.rb +59 -0
- data/lib/faastruby/cli/commands/account/signup.rb +76 -0
- data/lib/faastruby/cli/commands/{function.rb → function/base_command.rb} +2 -11
- data/lib/faastruby/cli/commands/function/build.rb +18 -11
- data/lib/faastruby/cli/commands/function/deploy_to.rb +100 -37
- data/lib/faastruby/cli/commands/function/new.rb +89 -36
- data/lib/faastruby/cli/commands/function/remove_from.rb +21 -6
- data/lib/faastruby/cli/commands/function/run.rb +15 -15
- data/lib/faastruby/cli/commands/function/test.rb +5 -4
- data/lib/faastruby/cli/commands/function/update_context.rb +10 -3
- data/lib/faastruby/cli/commands/function/upgrade.rb +62 -61
- data/lib/faastruby/cli/commands/help.rb +33 -20
- data/lib/faastruby/cli/commands/project/base_command.rb +14 -0
- data/lib/faastruby/cli/commands/project/deploy.rb +114 -0
- data/lib/faastruby/cli/commands/project/down.rb +58 -0
- data/lib/faastruby/cli/commands/project/new.rb +237 -0
- data/lib/faastruby/cli/commands/workspace/cp.rb +107 -0
- data/lib/faastruby/cli/commands/workspace/create.rb +35 -27
- data/lib/faastruby/cli/commands/workspace/destroy.rb +14 -7
- data/lib/faastruby/cli/commands/workspace/list.rb +15 -6
- data/lib/faastruby/cli/commands/workspace/migrate.rb +93 -0
- data/lib/faastruby/cli/commands/workspace/rm.rb +81 -0
- data/lib/faastruby/cli/commands/workspace/update.rb +62 -0
- data/lib/faastruby/cli/credentials.rb +58 -57
- data/lib/faastruby/cli/new_credentials.rb +63 -0
- data/lib/faastruby/cli/package.rb +1 -0
- data/lib/faastruby/cli/template.rb +7 -7
- data/lib/faastruby/local.rb +188 -0
- data/lib/faastruby/local/crystal_runtime.cr +170 -0
- data/lib/faastruby/local/functions.rb +7 -0
- data/lib/faastruby/local/functions/crystal.rb +64 -0
- data/lib/faastruby/local/functions/function.rb +173 -0
- data/lib/faastruby/local/functions/ruby.rb +28 -0
- data/lib/faastruby/local/listeners.rb +5 -0
- data/lib/faastruby/local/listeners/listener.rb +104 -0
- data/lib/faastruby/local/logger.rb +37 -0
- data/lib/faastruby/local/monkey_patch.rb +38 -0
- data/lib/faastruby/local/processors.rb +7 -0
- data/lib/faastruby/local/processors/function.rb +151 -0
- data/lib/faastruby/local/processors/processor.rb +116 -0
- data/lib/faastruby/local/processors/static_file.rb +48 -0
- data/lib/faastruby/local/static_files.rb +5 -0
- data/lib/faastruby/local/static_files/static_file.rb +59 -0
- data/lib/faastruby/server.rb +44 -3
- data/lib/faastruby/server/app.rb +107 -0
- data/lib/faastruby/server/concurrency_controller.rb +50 -50
- data/lib/faastruby/server/config.ru +2 -0
- data/lib/faastruby/server/event.rb +3 -0
- data/lib/faastruby/server/event_hub.rb +7 -6
- data/lib/faastruby/server/local.rb +22 -0
- data/lib/faastruby/server/logger.rb +50 -0
- data/lib/faastruby/server/project_config.rb +44 -0
- data/lib/faastruby/server/puma.rb +4 -0
- data/lib/faastruby/server/response.rb +40 -0
- data/lib/faastruby/server/runner.rb +116 -21
- data/lib/faastruby/server/runner_methods.rb +17 -16
- data/lib/faastruby/server/sentinel.rb +496 -0
- data/lib/faastruby/supported_runtimes.rb +8 -0
- data/lib/faastruby/user.rb +77 -0
- data/lib/faastruby/version.rb +1 -1
- data/lib/faastruby/workspace.rb +36 -3
- data/templates/crystal/example-blank/handler.cr +3 -0
- data/templates/crystal/example/spec/handler_spec.cr +11 -6
- data/templates/public-web/assets/images/background.png +0 -0
- data/templates/public-web/assets/images/ruby.png +0 -0
- data/templates/public-web/assets/javascripts/main.js +1 -0
- data/templates/public-web/assets/stylesheets/main.css +70 -0
- data/templates/public-web/favicon.ico +0 -0
- data/templates/ruby/api-404/handler.rb +6 -0
- data/templates/ruby/api-root/handler.rb +6 -0
- data/templates/ruby/example-blank/handler.rb +0 -23
- data/templates/ruby/web-404/404.html +36 -0
- data/templates/ruby/web-404/handler.rb +3 -0
- data/templates/ruby/web-root/handler.rb +10 -0
- data/templates/ruby/web-root/index.html.erb +37 -0
- data/templates/ruby/web-root/template.rb +13 -0
- metadata +102 -21
- data/exe/faastruby-server +0 -76
- data/lib/faastruby/cli/commands/credentials.rb +0 -11
- data/lib/faastruby/cli/commands/credentials/add.rb +0 -58
- data/lib/faastruby/cli/commands/credentials/list.rb +0 -58
- data/lib/faastruby/cli/commands/workspace.rb +0 -13
- data/lib/faastruby/cli/commands/workspace/deploy.rb +0 -50
- data/templates/crystal/example-blank/README.md +0 -22
- data/templates/crystal/example-blank/spec/handler_spec.cr +0 -8
- data/templates/crystal/example-blank/spec/spec_helper.cr +0 -4
- data/templates/crystal/example-blank/src/handler.cr +0 -25
- data/templates/ruby/example-blank/Gemfile +0 -7
- data/templates/ruby/example-blank/README.md +0 -22
- data/templates/ruby/example-blank/spec/handler_spec.rb +0 -16
- data/templates/ruby/example-blank/spec/spec_helper.rb +0 -3
@@ -0,0 +1,59 @@
|
|
1
|
+
module FaaStRuby
|
2
|
+
module Command
|
3
|
+
module Account
|
4
|
+
require 'faastruby/cli/commands/account/base_command'
|
5
|
+
class Logout < AccountBaseCommand
|
6
|
+
def initialize(args)
|
7
|
+
@args = args
|
8
|
+
parse_options
|
9
|
+
@credentials_file = NewCredentials::CredentialsFile.new
|
10
|
+
@credentials = @credentials_file.get
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
user = User.new(@credentials)
|
15
|
+
unless user.has_credentials?
|
16
|
+
puts "Logout successful."
|
17
|
+
exit 0
|
18
|
+
end
|
19
|
+
user.logout(all: @options['all'])
|
20
|
+
FaaStRuby::CLI.error(user.errors) if !@options['force'] && user&.errors.any?
|
21
|
+
@credentials_file.clear
|
22
|
+
puts "Logout successful."
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.help
|
26
|
+
"logout [ARGS]"
|
27
|
+
end
|
28
|
+
|
29
|
+
def usage
|
30
|
+
puts "Usage: faastruby #{self.class.help}"
|
31
|
+
puts %(
|
32
|
+
-a,--all # Logout from all machines
|
33
|
+
-f,--force # Logout from all machines
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def parse_options
|
40
|
+
@options = {}
|
41
|
+
while @args.any?
|
42
|
+
option = @args.shift
|
43
|
+
case option
|
44
|
+
when '-h', '--help', 'help'
|
45
|
+
usage
|
46
|
+
exit 0
|
47
|
+
when '-f', '--force'
|
48
|
+
@options['force'] = true
|
49
|
+
when '-a', '--all'
|
50
|
+
@options['all'] = true
|
51
|
+
else
|
52
|
+
FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module FaaStRuby
|
2
|
+
module Command
|
3
|
+
module Account
|
4
|
+
PASSWORD_REGEX = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,20}$/
|
5
|
+
EMAIL_REGEX = /\A([\w+\-].?)+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
|
6
|
+
require 'faastruby/cli/commands/account/base_command'
|
7
|
+
require 'io/console'
|
8
|
+
class Signup < AccountBaseCommand
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
parse_options
|
12
|
+
FaaStRuby::CLI.error("You are currently logged in. Please run 'faastruby logout' to logout, then try again.") if has_user_logged_in?
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
puts "\nWelcome to FaaStRuby! Please enter your email address:"
|
17
|
+
print "Email: "
|
18
|
+
email = STDIN.gets.chomp
|
19
|
+
until email_is_valid?(email) do
|
20
|
+
puts "You entered an invalid email address. Please try again:".red
|
21
|
+
print "Email: "
|
22
|
+
email = STDIN.gets.chomp
|
23
|
+
end
|
24
|
+
puts "\nNow type in a password. It must contain 8 to 20 characters and have at least one uppercase letter, one lowercase letter, one number."
|
25
|
+
print "Password: "
|
26
|
+
password = STDIN.noecho(&:gets).chomp
|
27
|
+
until password_is_valid?(password) do
|
28
|
+
puts "\nYour password must contain 8 to 20 characters and have at least one uppercase letter, one lowercase letter, one number. Please try again:".red
|
29
|
+
print "Password: "
|
30
|
+
password = STDIN.noecho(&:gets).chomp
|
31
|
+
end
|
32
|
+
spinner = spin("Creating your account...")
|
33
|
+
user = User.create(email: email, password: password)
|
34
|
+
if user.errors.any?
|
35
|
+
spinner.stop(" Failed :(")
|
36
|
+
FaaStRuby::CLI.error(user.errors)
|
37
|
+
end
|
38
|
+
spinner.stop(' Done!')
|
39
|
+
exec("faastruby confirm-account --email #{email}")
|
40
|
+
exit 0
|
41
|
+
end
|
42
|
+
|
43
|
+
def email_is_valid?(email)
|
44
|
+
email.match(EMAIL_REGEX)
|
45
|
+
end
|
46
|
+
|
47
|
+
def password_is_valid?(password)
|
48
|
+
password.match(PASSWORD_REGEX)
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.help
|
52
|
+
"signup"
|
53
|
+
end
|
54
|
+
|
55
|
+
def usage
|
56
|
+
puts "Usage: faastruby #{self.class.help}"
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def parse_options
|
61
|
+
@options = {}
|
62
|
+
while @args.any?
|
63
|
+
option = @args.shift
|
64
|
+
case option
|
65
|
+
when '-h', '--help', 'help'
|
66
|
+
usage
|
67
|
+
exit 0
|
68
|
+
else
|
69
|
+
FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -12,20 +12,11 @@ module FaaStRuby
|
|
12
12
|
# deploy: false
|
13
13
|
def load_yaml
|
14
14
|
FaaStRuby::CLI.error("It looks like you created this function with an old version of faastruby. Please run 'faastruby upgrade'.") if File.file?('handler.rb') && !File.file?('faastruby.yml')
|
15
|
-
FaaStRuby::CLI.error("Could not find file 'faastruby.yml' in the current directory")
|
15
|
+
FaaStRuby::CLI.error("Could not find file 'faastruby.yml' in the current directory") if !File.file?('faastruby.yml') && @options['function_name'].nil?
|
16
16
|
@yaml_config = YAML.load(File.read('./faastruby.yml'))
|
17
17
|
FaaStRuby::CLI.error("Could read function name from 'faastruby.yml'. Make sure you have a key 'name: FUNCTION_NAME' in that file!") unless @yaml_config['name']
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
end
|
23
|
-
|
24
|
-
require 'faastruby/cli/commands/function/build'
|
25
|
-
require 'faastruby/cli/commands/function/deploy_to'
|
26
|
-
require 'faastruby/cli/commands/function/new'
|
27
|
-
require 'faastruby/cli/commands/function/remove_from'
|
28
|
-
require 'faastruby/cli/commands/function/test'
|
29
|
-
require 'faastruby/cli/commands/function/update_context'
|
30
|
-
require 'faastruby/cli/commands/function/upgrade'
|
31
|
-
require 'faastruby/cli/commands/function/run'
|
22
|
+
end
|
@@ -1,23 +1,27 @@
|
|
1
1
|
module FaaStRuby
|
2
2
|
module Command
|
3
3
|
module Function
|
4
|
+
require 'faastruby/cli/commands/function/base_command'
|
5
|
+
require 'faastruby/cli/package'
|
4
6
|
class Build < FunctionBaseCommand
|
5
|
-
|
6
|
-
|
7
|
-
spinner = spin(
|
7
|
+
def self.build(source, output_file, function_name, quiet = false)
|
8
|
+
# msg = "[#{function_name}] Building package..."
|
9
|
+
# quiet ? puts(msg) : spinner = spin(msg)
|
8
10
|
FaaStRuby::Package.new(source, output_file).build
|
9
|
-
spinner.stop('Done!')
|
11
|
+
# quiet ? puts("[#{function_name}] Package created.") : spinner.stop('Done!')
|
10
12
|
puts "+ f #{output_file}".green unless quiet
|
11
13
|
end
|
12
14
|
|
13
15
|
def initialize(args)
|
14
16
|
@args = args
|
15
17
|
load_yaml
|
18
|
+
@yaml_config['before_build'] ||= []
|
16
19
|
@function_name = @yaml_config['name']
|
17
20
|
@abort_when_tests_fail = @yaml_config['abort_build_when_tests_fail']
|
18
21
|
parse_options
|
19
22
|
@options['source'] ||= '.'
|
20
|
-
@
|
23
|
+
@package_file = Tempfile.new('package')
|
24
|
+
@options['output_file'] ||= @package_file.path
|
21
25
|
end
|
22
26
|
|
23
27
|
def ruby_runtime?
|
@@ -37,8 +41,10 @@ module FaaStRuby
|
|
37
41
|
end
|
38
42
|
tests_passed = run_tests
|
39
43
|
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
|
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
|
44
|
+
puts "[#{@function_name}] Warning: Ignoring failed tests because you have 'abort_build_when_tests_fail: false' in 'faastruby.yml'".yellow if !tests_passed && !@abort_when_tests_fail
|
41
45
|
build(@options['source'], @options['output_file'])
|
46
|
+
@package_file.close
|
47
|
+
@package_file.unlink
|
42
48
|
end
|
43
49
|
|
44
50
|
def self.help
|
@@ -52,27 +58,28 @@ module FaaStRuby
|
|
52
58
|
private
|
53
59
|
|
54
60
|
def build(source, output_file)
|
55
|
-
spinner = spin("Running '
|
56
|
-
@yaml_config['
|
61
|
+
spinner = spin("[#{@function_name}] Running 'before_build' tasks...")
|
62
|
+
@yaml_config['before_build']&.each do |command|
|
57
63
|
puts `#{command}`
|
58
64
|
end
|
59
65
|
spinner.stop(' Done!')
|
60
|
-
self.class.build(source, output_file)
|
66
|
+
self.class.build(source, output_file, @function_name)
|
61
67
|
end
|
62
68
|
|
63
69
|
def shards_install
|
64
|
-
puts '[build] Verifying dependencies'
|
65
70
|
return true unless File.file?('shard.yml')
|
71
|
+
puts "[#{@function_name}] [build] Verifying dependencies"
|
66
72
|
system('shards check') || system('shards install')
|
67
73
|
end
|
68
74
|
|
69
75
|
def bundle_install
|
70
|
-
puts '[build] Verifying dependencies'
|
71
76
|
return true unless File.file?('Gemfile')
|
77
|
+
puts "[#{@function_name}] [build] Verifying dependencies"
|
72
78
|
system('bundle check') || system('bundle install')
|
73
79
|
end
|
74
80
|
|
75
81
|
def run_tests
|
82
|
+
require 'faastruby/cli/commands/function/test'
|
76
83
|
FaaStRuby::Command::Function::Test.new(true).run(do_not_exit: true)
|
77
84
|
end
|
78
85
|
|
@@ -1,16 +1,26 @@
|
|
1
1
|
module FaaStRuby
|
2
2
|
module Command
|
3
3
|
module Function
|
4
|
+
require 'faastruby/cli/commands/function/base_command'
|
5
|
+
require 'faastruby/cli/new_credentials'
|
4
6
|
class DeployTo < FunctionBaseCommand
|
5
7
|
def initialize(args)
|
6
8
|
@args = args
|
9
|
+
help
|
7
10
|
@missing_args = []
|
8
11
|
FaaStRuby::CLI.error(@missing_args, color: nil) if missing_args.any?
|
9
12
|
@workspace_name = @args.shift
|
13
|
+
parse_options
|
10
14
|
load_yaml
|
15
|
+
@yaml_config['before_build'] ||= []
|
11
16
|
@function_name = @yaml_config['name']
|
12
|
-
|
13
|
-
|
17
|
+
unless @yaml_config['serve_static']
|
18
|
+
@options['root_to'] = @function_name if @options['is_root']
|
19
|
+
@options['catch_all'] = @function_name if @options['is_catch_all']
|
20
|
+
# @abort_when_tests_fail = true #@yaml_config['abort_deploy_when_tests_fail']
|
21
|
+
end
|
22
|
+
load_credentials
|
23
|
+
@package_file = Tempfile.new('package')
|
14
24
|
end
|
15
25
|
|
16
26
|
def ruby_runtime?
|
@@ -18,69 +28,92 @@ module FaaStRuby
|
|
18
28
|
end
|
19
29
|
|
20
30
|
def crystal_runtime?
|
31
|
+
return false if @yaml_config['runtime'].nil?
|
21
32
|
@yaml_config['runtime'].match(/^crystal/)
|
22
33
|
end
|
23
34
|
|
35
|
+
def runtime_name
|
36
|
+
return 'Ruby' if ruby_runtime?
|
37
|
+
return 'Crystal' if crystal_runtime?
|
38
|
+
return 'Ruby'
|
39
|
+
end
|
40
|
+
|
24
41
|
def run
|
25
42
|
create_or_use_workspace
|
26
|
-
if
|
27
|
-
|
43
|
+
if @yaml_config['serve_static']
|
44
|
+
package_file_name = build_package
|
45
|
+
spinner = say("[#{@function_name}] Deploying static files '#{@function_name}' to workspace '#{@workspace_name}'...", quiet: @options['quiet'])
|
46
|
+
workspace = FaaStRuby::Workspace.new(name: @workspace_name).deploy(package_file_name)
|
47
|
+
else
|
48
|
+
if ruby_runtime?
|
49
|
+
FaaStRuby::CLI.error('Please fix the problems above and try again') unless bundle_install
|
50
|
+
end
|
51
|
+
if crystal_runtime?
|
52
|
+
FaaStRuby::CLI.error('Please fix the problems above and try again') unless shards_install
|
53
|
+
end
|
54
|
+
FaaStRuby::CLI.error("[#{@function_name}] Deploy aborted because 'test_command' exited non-zero.") unless run_tests
|
55
|
+
package_file_name = build_package
|
56
|
+
spinner = say("[#{@function_name}] Deploying #{runtime_name} function '#{@function_name}' to workspace '#{@workspace_name}'...", quiet: @options['quiet'])
|
57
|
+
workspace = FaaStRuby::Workspace.new(name: @workspace_name).deploy(package_file_name, root_to: @options['root_to'], catch_all: @options['catch_all'], context: @options['context'])
|
28
58
|
end
|
29
|
-
if crystal_runtime?
|
30
|
-
FaaStRuby::CLI.error('Please fix the problems above and try again') unless shards_install
|
31
|
-
end
|
32
|
-
tests_passed = run_tests
|
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
|
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
|
35
|
-
package_file_name = build_package
|
36
|
-
spinner = spin("Deploying '#{@workspace_name}/#{@function_name}'")
|
37
|
-
workspace = FaaStRuby::Workspace.new(name: @workspace_name).deploy(package_file_name)
|
38
59
|
if workspace.errors.any?
|
39
|
-
spinner
|
60
|
+
puts ' Failed :(' unless spinner&.stop(' Failed :(')
|
61
|
+
@package_file.unlink
|
40
62
|
FaaStRuby::CLI.error(workspace.errors)
|
41
63
|
end
|
42
|
-
spinner.stop('Done!')
|
43
|
-
|
64
|
+
spinner.stop(' Done!') unless @options['quiet']
|
65
|
+
@package_file.unlink
|
66
|
+
puts "* [#{@function_name}] Deploy OK".green
|
67
|
+
unless @yaml_config['serve_static']
|
68
|
+
puts "* [#{@function_name}] Workspace: #{@workspace_name}".green
|
69
|
+
puts "* [#{@function_name}] Endpoint: #{FaaStRuby.workspace_host_for(@workspace_name)}/#{@function_name unless @options['root_to']}".green
|
70
|
+
end
|
71
|
+
puts '---'
|
44
72
|
exit 0
|
45
73
|
end
|
46
74
|
|
47
75
|
def self.help
|
48
|
-
"deploy-to
|
76
|
+
"deploy-to WORKSPACE_NAME [ARGS]"
|
49
77
|
end
|
50
78
|
|
51
79
|
def usage
|
52
|
-
"
|
80
|
+
puts "\nUsage: faastruby #{self.class.help}"
|
81
|
+
puts %(
|
82
|
+
-f,--function PATH/TO/FUNCTION # Specify the directory where the function is.
|
83
|
+
--context DATA # The data to be stored as context in the cloud,
|
84
|
+
# accessible via 'event.context' from within your function.
|
85
|
+
--set-root # Set the function as the root route of the workspace/
|
86
|
+
--set-catch-all # Set the function as the catch-all route of the workspace.
|
87
|
+
--dont-create-workspace # Don't try to create the workspace if it doesn't exist.
|
88
|
+
)
|
53
89
|
end
|
54
90
|
|
55
91
|
private
|
56
92
|
|
57
|
-
def load_credentials(exit_on_error:)
|
58
|
-
@has_credentials = FaaStRuby::Credentials.load_for(@workspace_name, exit_on_error: exit_on_error)
|
59
|
-
end
|
60
|
-
|
61
93
|
def create_or_use_workspace
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
94
|
+
return true if @options['dont_create_workspace']
|
95
|
+
require 'faastruby/cli/commands/workspace/create'
|
96
|
+
# puts "[#{@function_name}] Attemping to create workspace '#{@workspace_name}'"
|
97
|
+
cmd = FaaStRuby::Command::Workspace::Create.new([@workspace_name])
|
98
|
+
result = cmd.run(create_directory: false, exit_on_error: false)
|
99
|
+
if result
|
67
100
|
# Give a little bit of time after creating the workspace
|
68
101
|
# for consistency. This is temporary until the API gets patched.
|
69
|
-
spinner =
|
102
|
+
spinner = say("[#{@function_name}] Waiting for the workspace '#{@workspace_name}' to be ready...", quiet: @options['quiet'])
|
70
103
|
sleep 2
|
71
|
-
spinner
|
104
|
+
puts ' Done!' unless spinner&.stop(' Done!')
|
72
105
|
end
|
73
106
|
end
|
74
107
|
|
75
108
|
def shards_install
|
76
|
-
puts '[build] Verifying dependencies'
|
77
109
|
return true unless File.file?('shard.yml')
|
110
|
+
puts "[#{@function_name}] [build] Verifying dependencies"
|
78
111
|
system('shards check') || system('shards install')
|
79
112
|
end
|
80
113
|
|
81
114
|
def bundle_install
|
82
|
-
puts '[build] Verifying dependencies'
|
83
115
|
return true unless File.file?('Gemfile')
|
116
|
+
puts "[#{@function_name}] [build] Verifying dependencies"
|
84
117
|
system('bundle check') || system('bundle install')
|
85
118
|
end
|
86
119
|
|
@@ -94,20 +127,50 @@ module FaaStRuby
|
|
94
127
|
end
|
95
128
|
|
96
129
|
def run_tests
|
130
|
+
return true unless @yaml_config['test_command']
|
131
|
+
require 'faastruby/cli/commands/function/test'
|
97
132
|
FaaStRuby::Command::Function::Test.new(true).run(do_not_exit: true)
|
98
133
|
end
|
99
134
|
|
100
135
|
def build_package
|
101
136
|
source = '.'
|
102
|
-
output_file =
|
103
|
-
|
104
|
-
|
105
|
-
|
137
|
+
output_file = @package_file.path
|
138
|
+
if @yaml_config['before_build'].any?
|
139
|
+
spinner = say("[#{@function_name}] Running 'before_build' tasks...", quiet: @options['quiet'])
|
140
|
+
@yaml_config['before_build']&.each do |command|
|
141
|
+
puts `#{command}`
|
142
|
+
end
|
143
|
+
spinner&.stop(' Done!')
|
106
144
|
end
|
107
|
-
|
108
|
-
FaaStRuby::Command::Function::Build.build(source, output_file, true)
|
145
|
+
require 'faastruby/cli/commands/function/build'
|
146
|
+
FaaStRuby::Command::Function::Build.build(source, output_file, @function_name, true)
|
147
|
+
@package_file.close
|
109
148
|
output_file
|
110
149
|
end
|
150
|
+
|
151
|
+
def parse_options
|
152
|
+
@options = {}
|
153
|
+
while @args.any?
|
154
|
+
option = @args.shift
|
155
|
+
case option
|
156
|
+
when '-f', '--function'
|
157
|
+
Dir.chdir @args.shift
|
158
|
+
when '--context'
|
159
|
+
@options['context'] = @args.shift
|
160
|
+
when '--quiet', '-q'
|
161
|
+
@options['quiet'] = true
|
162
|
+
when '--set-root'
|
163
|
+
@options['is_root'] = true
|
164
|
+
when '--set-catch-all'
|
165
|
+
@options['is_catch_all'] = true
|
166
|
+
when '--dont-create-workspace'
|
167
|
+
@options['dont_create_workspace'] = true
|
168
|
+
else
|
169
|
+
FaaStRuby::CLI.error("Unknown argument: #{option}")
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
111
174
|
end
|
112
175
|
end
|
113
176
|
end
|
@@ -1,21 +1,33 @@
|
|
1
|
+
require 'erb'
|
1
2
|
module FaaStRuby
|
3
|
+
require 'faastruby/version'
|
2
4
|
module Command
|
3
5
|
module Function
|
6
|
+
require 'faastruby/supported_runtimes'
|
7
|
+
require 'faastruby/cli/commands/function/base_command'
|
8
|
+
require 'faastruby/cli/template'
|
4
9
|
class New < FunctionBaseCommand
|
5
10
|
def initialize(args)
|
6
11
|
@args = args
|
12
|
+
help
|
7
13
|
@missing_args = []
|
8
14
|
FaaStRuby::CLI.error(@missing_args, color: nil) if missing_args.any?
|
9
15
|
@function_name = @args.shift
|
16
|
+
FaaStRuby::CLI.error("The function name must have at least one character and can only contain letters, numbers, -, _, . and /. Names with just a period are not allowed. Invalid name: #{@function_name}") unless name_valid?
|
10
17
|
parse_options
|
11
18
|
@base_dir ||= @function_name
|
12
19
|
@options['runtime_name'] ||= 'ruby'
|
13
20
|
@options['runtime_version'] ||= '2.5.3'
|
14
|
-
|
21
|
+
if @options['blank_template']
|
22
|
+
@options['template'] = FaaStRuby::Template.new(type: 'local', source: Template.gem_template_path_for('example-blank', runtime: @options['runtime_name'] || 'ruby'))
|
23
|
+
else
|
24
|
+
@options['template'] ||= FaaStRuby::Template.new(type: 'local', source: Template.gem_template_path_for('example', runtime: @options['runtime_name']))
|
25
|
+
end
|
15
26
|
end
|
16
27
|
|
17
|
-
def run
|
18
|
-
@options['
|
28
|
+
def run(print_base_dir: false, blank_template: false)
|
29
|
+
@options['blank_template'] ||= blank_template
|
30
|
+
@options['template'].install(to: @base_dir, force: @options['force'], print_base_dir: print_base_dir)
|
19
31
|
faastruby_yaml = "#{@base_dir}/faastruby.yml"
|
20
32
|
if File.file?(faastruby_yaml)
|
21
33
|
@yaml_content = YAML.load(File.read(faastruby_yaml))
|
@@ -26,32 +38,28 @@ module FaaStRuby
|
|
26
38
|
else
|
27
39
|
@yaml_content = yaml_for(@options['runtime_name'])
|
28
40
|
end
|
29
|
-
write_yaml
|
41
|
+
write_yaml(print_base_dir: print_base_dir)
|
30
42
|
post_tasks(@options['runtime_name'])
|
31
43
|
end
|
32
44
|
|
33
45
|
def self.help
|
34
|
-
"new
|
35
|
-
<<-EOS
|
36
|
-
|
37
|
-
--blank
|
38
|
-
Create a blank function
|
39
|
-
--force
|
40
|
-
Continue if directory already exists and overwrite files
|
41
|
-
-g
|
42
|
-
Initialize a Git repository.
|
43
|
-
--runtime
|
44
|
-
Choose the runtime. Options are: #{SUPPORTED_RUNTIMES.join(', ')}
|
45
|
-
--template TYPE(local|git|github):SOURCE
|
46
|
-
Use another function as template. Examples:
|
47
|
-
--template local:/path/to/folder
|
48
|
-
--template git:git@github.com:user/repo.git
|
49
|
-
--template github:user/repo
|
50
|
-
EOS
|
46
|
+
"new FUNCTION_NAME [ARGS]"
|
51
47
|
end
|
52
48
|
|
53
49
|
def usage
|
54
|
-
"
|
50
|
+
puts "\nUsage: faastruby #{self.class.help}"
|
51
|
+
puts %(
|
52
|
+
--blank # Create a blank function
|
53
|
+
--force # Continue if directory already exists and overwrite files
|
54
|
+
-g, --git # Initialize a Git repository.
|
55
|
+
--runtime # Set the language runtime.
|
56
|
+
# Options are: #{SUPPORTED_RUNTIMES.join(', ')}
|
57
|
+
--template TYPE(local|git|github):SOURCE # Initialize the function using a template
|
58
|
+
# Examples:
|
59
|
+
# --template local:/path/to/folder
|
60
|
+
# --template git:git@github.com:user/repo.git
|
61
|
+
# --template github:user/repo
|
62
|
+
)
|
55
63
|
end
|
56
64
|
|
57
65
|
private
|
@@ -61,7 +69,7 @@ EOS
|
|
61
69
|
while @args.any?
|
62
70
|
option = @args.shift
|
63
71
|
case option
|
64
|
-
when '-g'
|
72
|
+
when '-g', '--git'
|
65
73
|
@options['git_init'] = true
|
66
74
|
when '--template'
|
67
75
|
FaaStRuby::CLI.error("Option '--template' can't be used with '--blank' or '--runtime'.".red) if @options['runtime'] || @options['blank_template']
|
@@ -70,7 +78,7 @@ EOS
|
|
70
78
|
source = source.join(':')
|
71
79
|
@options['template'] = FaaStRuby::Template.new(type: type, source: source)
|
72
80
|
when '--runtime'
|
73
|
-
FaaStRuby::CLI.error("Option '--
|
81
|
+
FaaStRuby::CLI.error("Option '--runtime' can't be used with '--template' or '--blank'.".red) if @options['template']
|
74
82
|
@options['runtime'] = @args.shift
|
75
83
|
@options['runtime_name'], @options['runtime_version'] = @options['runtime'].split(':')
|
76
84
|
template_name = @options['blank_template'] ? 'example-blank' : 'example'
|
@@ -79,9 +87,9 @@ EOS
|
|
79
87
|
when '-f', '--force'
|
80
88
|
@options['force'] = true
|
81
89
|
when '--blank'
|
82
|
-
|
90
|
+
@options['template'] = nil
|
91
|
+
FaaStRuby::CLI.error("Option '--blank' can't be used with '--blank' or '--template'.".red) if @options['template']
|
83
92
|
@options['blank_template'] = true
|
84
|
-
@options['template'] = FaaStRuby::Template.new(type: 'local', source: Template.gem_template_path_for('example-blank', runtime: @options['runtime_name'] || 'ruby'))
|
85
93
|
else
|
86
94
|
FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
|
87
95
|
end
|
@@ -96,6 +104,28 @@ EOS
|
|
96
104
|
@missing_args
|
97
105
|
end
|
98
106
|
|
107
|
+
def yaml_comments
|
108
|
+
[
|
109
|
+
'## You can add commands to run locally before building the deployment package.',
|
110
|
+
"## Some use cases are:",
|
111
|
+
"## * minifying Javascript/CSS",
|
112
|
+
"## * downloading a file to be included in the package.",
|
113
|
+
"# before_build:",
|
114
|
+
"# - curl https://some.url --output some.file",
|
115
|
+
"# - uglifyjs your.js -c -m -o your.min.js",
|
116
|
+
'',
|
117
|
+
'# To schedule periodic runs, follow the example below:',
|
118
|
+
'# schedule:',
|
119
|
+
'# job1:',
|
120
|
+
'# when: every 2 hours',
|
121
|
+
'# body: {"foo": "bar"}',
|
122
|
+
'# method: POST',
|
123
|
+
'# query_params: {"param": "value"}',
|
124
|
+
'# headers: {"Content-Type": "application/json"}',
|
125
|
+
'# job2: ...'
|
126
|
+
].join("\n")
|
127
|
+
end
|
128
|
+
|
99
129
|
def yaml_for(runtime_name)
|
100
130
|
case runtime_name
|
101
131
|
when 'crystal'
|
@@ -105,21 +135,29 @@ EOS
|
|
105
135
|
else
|
106
136
|
test_command = 'rspec'
|
107
137
|
end
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
138
|
+
if @options['blank_template']
|
139
|
+
{
|
140
|
+
'cli_version' => FaaStRuby::VERSION,
|
141
|
+
'name' => @function_name,
|
142
|
+
'runtime' => @options['runtime'] || 'ruby:2.5.3'
|
143
|
+
}
|
144
|
+
else
|
145
|
+
{
|
146
|
+
'cli_version' => FaaStRuby::VERSION,
|
147
|
+
'name' => @function_name,
|
148
|
+
'before_build' => [],
|
149
|
+
'runtime' => @options['runtime'] || 'ruby:2.5.3',
|
150
|
+
'test_command' => test_command
|
151
|
+
}
|
152
|
+
end
|
116
153
|
end
|
117
154
|
|
118
|
-
def write_yaml
|
119
|
-
write_file("#{@function_name}/faastruby.yml", @yaml_content.to_yaml)
|
155
|
+
def write_yaml(print_base_dir: false)
|
156
|
+
write_file("#{@function_name}/faastruby.yml", @yaml_content.to_yaml, print_base_dir: print_base_dir, extra_content: yaml_comments)
|
120
157
|
end
|
121
158
|
|
122
159
|
def post_tasks(runtime_name)
|
160
|
+
return true if @options['blank_template']
|
123
161
|
update_readme
|
124
162
|
puts `git init #{@base_dir}` if @options['git_init']
|
125
163
|
case runtime_name
|
@@ -141,6 +179,7 @@ EOS
|
|
141
179
|
end
|
142
180
|
|
143
181
|
def bundle_install
|
182
|
+
return true unless File.file?("#{@base_dir}/Gemfile")
|
144
183
|
spinner = spin("Installing gems...")
|
145
184
|
system("bundle install --gemfile=#{@base_dir}/Gemfile > /dev/null")
|
146
185
|
spinner.stop('Done!')
|
@@ -167,10 +206,24 @@ EOS
|
|
167
206
|
end
|
168
207
|
|
169
208
|
def shards_install
|
209
|
+
return true unless File.file?("#{@base_dir}/shard.yml")
|
170
210
|
spinner = spin("Installing shards...")
|
171
211
|
system("cd #{@base_dir} && shards install > /dev/null")
|
172
212
|
spinner.stop('Done!')
|
173
213
|
end
|
214
|
+
|
215
|
+
def name_valid?
|
216
|
+
return false unless @function_name.match(/^#{FUNCTION_NAME_REGEX}$/)
|
217
|
+
while @function_name.match(/\.\./) || @function_name.match(/^\.\//) || @function_name.match(/(^\/|\/$)/)
|
218
|
+
@function_name.gsub!('..', '.')
|
219
|
+
@function_name.gsub!(/^\.\//, '')
|
220
|
+
@function_name.gsub!(/(^\/|\/$)/, '')
|
221
|
+
end
|
222
|
+
if @function_name == '.' || @function_name == '' || @function_name.match(/\.\./)
|
223
|
+
return false
|
224
|
+
end
|
225
|
+
return true
|
226
|
+
end
|
174
227
|
end
|
175
228
|
end
|
176
229
|
end
|