faastruby 0.2.0

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 (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/CHANGELOG.md +11 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +67 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +39 -0
  8. data/Rakefile +2 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/example-blank/Gemfile +5 -0
  12. data/example-blank/handler.rb +4 -0
  13. data/example-blank/spec/handler_spec.rb +11 -0
  14. data/example-blank/spec/helpers/faastruby.rb +23 -0
  15. data/example-blank/spec/spec_helper.rb +2 -0
  16. data/example/Gemfile +5 -0
  17. data/example/handler.rb +17 -0
  18. data/example/spec/handler_spec.rb +20 -0
  19. data/example/spec/helpers/faastruby.rb +23 -0
  20. data/example/spec/spec_helper.rb +2 -0
  21. data/exe/faastruby +5 -0
  22. data/faastruby.gemspec +41 -0
  23. data/lib/faastruby.rb +6 -0
  24. data/lib/faastruby/api.rb +94 -0
  25. data/lib/faastruby/base.rb +53 -0
  26. data/lib/faastruby/cli.rb +42 -0
  27. data/lib/faastruby/cli/commands.rb +61 -0
  28. data/lib/faastruby/cli/commands/function.rb +31 -0
  29. data/lib/faastruby/cli/commands/function/build.rb +65 -0
  30. data/lib/faastruby/cli/commands/function/deploy.rb +62 -0
  31. data/lib/faastruby/cli/commands/function/new.rb +99 -0
  32. data/lib/faastruby/cli/commands/function/remove_from.rb +71 -0
  33. data/lib/faastruby/cli/commands/function/run.rb +135 -0
  34. data/lib/faastruby/cli/commands/function/test.rb +42 -0
  35. data/lib/faastruby/cli/commands/function/update_context.rb +67 -0
  36. data/lib/faastruby/cli/commands/function/upgrade.rb +69 -0
  37. data/lib/faastruby/cli/commands/help.rb +31 -0
  38. data/lib/faastruby/cli/commands/version.rb +13 -0
  39. data/lib/faastruby/cli/commands/workspace.rb +12 -0
  40. data/lib/faastruby/cli/commands/workspace/create.rb +70 -0
  41. data/lib/faastruby/cli/commands/workspace/destroy.rb +66 -0
  42. data/lib/faastruby/cli/commands/workspace/list.rb +54 -0
  43. data/lib/faastruby/cli/credentials.rb +49 -0
  44. data/lib/faastruby/cli/package.rb +46 -0
  45. data/lib/faastruby/function.rb +27 -0
  46. data/lib/faastruby/version.rb +3 -0
  47. data/lib/faastruby/workspace.rb +49 -0
  48. metadata +203 -0
@@ -0,0 +1,53 @@
1
+ module FaaStRuby
2
+ HOST = ENV['FAASTRUBY_HOST'] || 'https://api.faastruby.io'
3
+
4
+ class << self
5
+ attr_accessor :configuration
6
+ end
7
+
8
+ def self.api_key
9
+ configuration&.api_key || ENV['FAASTRUBY_API_KEY']
10
+ end
11
+
12
+ def self.api_secret
13
+ configuration&.api_secret || ENV['FAASTRUBY_API_SECRET']
14
+ end
15
+
16
+ def self.configure
17
+ self.configuration ||= Configuration.new
18
+ yield(configuration)
19
+ end
20
+
21
+ def self.credentials
22
+ {api_key: api_key, api_secret: api_secret}
23
+ end
24
+
25
+ class Configuration
26
+ attr_accessor :api_key, :api_secret
27
+ end
28
+
29
+
30
+ class BaseObject
31
+ def initialize(params = {}, &block)
32
+ @errors = []
33
+ @api = API.new
34
+ self.mass_assign(params) if params
35
+ yield self if block_given?
36
+ end
37
+
38
+ def assign_attributes(params = {}, &block)
39
+ self.mass_assign(params) if params
40
+ yield self if block_given?
41
+ end
42
+
43
+ def attributes=(params)
44
+ assign_attributes(params)
45
+ end
46
+
47
+ def mass_assign(attrs)
48
+ attrs.each do |key, value|
49
+ self.public_send("#{key}=", value)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,42 @@
1
+ require 'yaml'
2
+ require 'tty-spinner'
3
+ require 'tty-table'
4
+ require 'zip'
5
+ require 'colorize'
6
+ require 'faastruby/cli/commands'
7
+ require 'faastruby/cli/package'
8
+
9
+ module FaaStRuby
10
+ FAASTRUBY_YAML = 'faastruby.yml'
11
+ FAASTRUBY_CREDENTIALS = File.expand_path(ENV['FAASTRUBY_CREDENTIALS'] || '~/.faastruby')
12
+ SPINNER_FORMAT = :spin_2
13
+
14
+ class CLI
15
+ def self.error(message, color: :red)
16
+ message.each {|m| STDERR.puts m.colorize(color)} if message.is_a?(Array)
17
+ STDERR.puts message.colorize(color) if message.is_a?(String)
18
+ exit 1
19
+ end
20
+
21
+ def self.run(command, args)
22
+ if command.nil?
23
+ FaaStRuby::Command::Help.new(args).run
24
+ return
25
+ end
26
+ check_version
27
+ error("Unknown command: #{command}") unless FaaStRuby::Command::COMMANDS.has_key?(command)
28
+ FaaStRuby::Command::COMMANDS[command].new(args).run
29
+ end
30
+
31
+ def self.check_version
32
+ latest = RestClient.get('https://faastruby.io/gem/minimum.txt').body rescue '0.0.1'
33
+ if Gem::Version.new(FaaStRuby::VERSION) < Gem::Version.new(latest)
34
+ FaaStRuby.error([
35
+ "You are using an old version of the gem. Please run 'gem update faastruby'.".red,
36
+ "Installed version: #{FaaStRuby::VERSION}",
37
+ "Latest version: #{latest}"
38
+ ], color: nil)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,61 @@
1
+ module FaaStRuby
2
+ module Command
3
+ class BaseCommand
4
+ def self.spin(message)
5
+ spinner = TTY::Spinner.new(":spinner #{message}", format: SPINNER_FORMAT)
6
+ spinner.auto_spin
7
+ spinner
8
+ end
9
+
10
+ def write_file(path, content, mode = 'w')
11
+ File.open(path, mode){|f| f.write(content) }
12
+ message = "#{mode == 'w' ? '+' : '~'} f #{path}"
13
+ puts message.green if mode == 'w'
14
+ puts message.yellow if mode == 'w+' || mode == 'a'
15
+ end
16
+
17
+ def spin(message)
18
+ spinner = TTY::Spinner.new(":spinner #{message}", format: SPINNER_FORMAT)
19
+ spinner.auto_spin
20
+ spinner
21
+ end
22
+
23
+ def load_yaml
24
+ return YAML.load(File.read(FAASTRUBY_YAML)) if File.file?(FAASTRUBY_YAML)
25
+ FaaStRuby.error("Could not find file #{FAASTRUBY_YAML}")
26
+ end
27
+
28
+ def spin(message)
29
+ self.class.spin(message)
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ require 'faastruby/cli/credentials'
36
+ require 'faastruby/cli/commands/function'
37
+ require 'faastruby/cli/commands/workspace'
38
+ require 'faastruby/cli/commands/help'
39
+ require 'faastruby/cli/commands/version'
40
+
41
+ module FaaStRuby
42
+ module Command
43
+ COMMANDS = {
44
+ 'new' => FaaStRuby::Command::Function::New,
45
+ 'deploy-to' => FaaStRuby::Command::Function::Deploy,
46
+ 'remove-from' => FaaStRuby::Command::Function::RemoveFrom,
47
+ 'update-context' => FaaStRuby::Command::Function::UpdateContext,
48
+ 'upgrade' => FaaStRuby::Command::Function::Upgrade,
49
+ 'build' => FaaStRuby::Command::Function::Build,
50
+ 'create-workspace' => FaaStRuby::Command::Workspace::Create,
51
+ 'destroy-workspace' => FaaStRuby::Command::Workspace::Destroy,
52
+ 'list-workspace' => FaaStRuby::Command::Workspace::List,
53
+ 'test' => FaaStRuby::Command::Function::Test,
54
+ 'run' => FaaStRuby::Command::Function::Run,
55
+ 'help' => FaaStRuby::Command::Help,
56
+ '-h' => FaaStRuby::Command::Help,
57
+ '--help' => FaaStRuby::Command::Help,
58
+ '-v' => FaaStRuby::Command::Version
59
+ }
60
+ end
61
+ end
@@ -0,0 +1,31 @@
1
+ require 'ostruct'
2
+ module FaaStRuby
3
+ module Command
4
+ module Function
5
+ class FunctionBaseCommand < BaseCommand
6
+ # --- Example YAML
7
+ # name: example
8
+ # test:
9
+ # command: "rspec"
10
+ # on_fail:
11
+ # build: false
12
+ # deploy: false
13
+ def load_yaml
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") unless File.file?('faastruby.yml')
16
+ @yaml_config = YAML.load(File.read('./faastruby.yml'))
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
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ require 'faastruby/cli/commands/function/build'
25
+ require 'faastruby/cli/commands/function/deploy'
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'
@@ -0,0 +1,65 @@
1
+ module FaaStRuby
2
+ module Command
3
+ module Function
4
+ class Build < FunctionBaseCommand
5
+
6
+ def self.build(source, output_file, quiet = false)
7
+ spinner = spin("Building package...")
8
+ FaaStRuby::Package.new(source, output_file).build
9
+ spinner.stop('Done!')
10
+ puts "+ f #{output_file}".green unless quiet
11
+ end
12
+
13
+ def initialize(args)
14
+ @args = args
15
+ load_yaml
16
+ @function_name = @yaml_config['name']
17
+ @abort_when_tests_fail = @yaml_config['abort_build_when_tests_fail']
18
+ parse_options
19
+ @options['source'] ||= '.'
20
+ @options['output_file'] ||= "#{@function_name}.zip"
21
+ end
22
+
23
+ def run
24
+ tests_passed = run_tests
25
+ 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
26
+ 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
27
+ build(@options['source'], @options['output_file'])
28
+ end
29
+
30
+ def self.help
31
+ "build".blue + " [-s, --source SOURCE_DIR] [-o, --output-file OUTPUT_FILE]"
32
+ end
33
+
34
+ def usage
35
+ "Usage: faastruby #{self.class.help}"
36
+ end
37
+
38
+ private
39
+
40
+ def build(source, output_file)
41
+ self.class.build(source, output_file)
42
+ end
43
+
44
+ def run_tests
45
+ FaaStRuby::Command::Function::Test.new(true).run(do_not_exit: true)
46
+ end
47
+
48
+ def parse_options
49
+ @options = {}
50
+ while @args.any?
51
+ option = @args.shift
52
+ case option
53
+ when '-s', '--source-dir'
54
+ @options['source'] = @args.shift
55
+ when '-o', '--output-file'
56
+ @options['output_file'] = @args.shift
57
+ else
58
+ FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,62 @@
1
+ module FaaStRuby
2
+ module Command
3
+ module Function
4
+ class Deploy < FunctionBaseCommand
5
+ def initialize(args)
6
+ @args = args
7
+ @missing_args = []
8
+ FaaStRuby::CLI.error(@missing_args, color: nil) if missing_args.any?
9
+ @workspace_name = @args.shift
10
+ load_yaml
11
+ @function_name = @yaml_config['name']
12
+ @abort_when_tests_fail = @yaml_config['abort_deploy_when_tests_fail']
13
+ FaaStRuby::Credentials.load_for(@workspace_name)
14
+ end
15
+
16
+ def run
17
+ tests_passed = run_tests
18
+ 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
19
+ 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
20
+ package_file_name = build_package
21
+ spinner = spin("Deploying to workspace '#{@workspace_name}'...")
22
+ workspace = FaaStRuby::Workspace.new(name: @workspace_name).deploy(package_file_name)
23
+ if workspace.errors.any?
24
+ spinner.stop('Failed :(')
25
+ FaaStRuby::CLI.error(workspace.errors)
26
+ end
27
+ spinner.stop('Done!')
28
+ end
29
+
30
+ def self.help
31
+ "deploy-to".blue + " WORKSPACE_NAME"
32
+ end
33
+
34
+ def usage
35
+ "Usage: faastruby #{self.class.help}"
36
+ end
37
+
38
+ private
39
+
40
+ def missing_args
41
+ if @args.empty?
42
+ @missing_args << "Missing argument: WORKSPACE_NAME".red
43
+ @missing_args << usage
44
+ end
45
+ FaaStRuby::CLI.error(["'#{@args.first}' is not a valid workspace name.".red, usage], color: nil) if @args.first =~ /^-.*/
46
+ @missing_args
47
+ end
48
+
49
+ def run_tests
50
+ FaaStRuby::Command::Function::Test.new(true).run(do_not_exit: true)
51
+ end
52
+
53
+ def build_package
54
+ source = '.'
55
+ output_file = "#{@function_name}.zip"
56
+ FaaStRuby::Command::Function::Build.build(source, output_file, true)
57
+ output_file
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,99 @@
1
+ module FaaStRuby
2
+ module Command
3
+ module Function
4
+ class New < FunctionBaseCommand
5
+ def initialize(args)
6
+ @args = args
7
+ @missing_args = []
8
+ FaaStRuby::CLI.error(@missing_args, color: nil) if missing_args.any?
9
+ @function_name = @args.shift
10
+ @base_dir = "./#{@function_name}"
11
+ @yaml_content = {
12
+ 'name' => @function_name,
13
+ 'test_command' => 'rspec',
14
+ 'abort_build_when_tests_fail' => true,
15
+ 'abort_deploy_when_tests_fail' => true
16
+ }
17
+ parse_options
18
+ @options['template'] ||= 'example'
19
+ end
20
+
21
+ def run
22
+ dir_exists? unless @options['force']
23
+ copy_template
24
+ write_yaml
25
+ bundle_install
26
+ end
27
+
28
+ def self.help
29
+ "new".blue + " FUNCTION_NAME [--blank] [--force]" +
30
+ <<-EOS
31
+
32
+ --blank # Create a blank function
33
+ --force # Continue if directory already exists and overwrite files
34
+ EOS
35
+ end
36
+
37
+ def usage
38
+ "Usage: faastruby #{self.class.help}"
39
+ end
40
+
41
+ private
42
+
43
+ def parse_options
44
+ @options = {}
45
+ while @args.any?
46
+ option = @args.shift
47
+ case option
48
+ when '-f', '--force'
49
+ @options['force'] = true
50
+ when '--blank'
51
+ @options['template'] = 'example-blank'
52
+ else
53
+ FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
54
+ end
55
+ end
56
+ end
57
+
58
+ def dir_exists?
59
+ return unless File.directory?(@base_dir)
60
+ print "The directory '#{@function_name}' already exists. Overwrite files? [y/N] "
61
+ response = STDIN.gets.chomp
62
+ FaaStRuby::CLI.error("Cancelled", color: nil) unless response == 'y'
63
+ end
64
+
65
+ def missing_args
66
+ if @args.empty?
67
+ @missing_args << "Missing argument: FUNCTION_NAME".red
68
+ @missing_args << usage
69
+ end
70
+ @missing_args
71
+ end
72
+
73
+ def copy_template
74
+ source = "#{Gem::Specification.find_by_name("faastruby").gem_dir}/#{@options['template']}"
75
+ FileUtils.mkdir_p(@base_dir)
76
+ FileUtils.cp_r("#{source}/.", "#{@base_dir}/")
77
+ puts "+ d #{@base_dir}".green
78
+ puts "+ d #{@base_dir}/spec".green
79
+ puts "+ d #{@base_dir}/spec/helpers".green
80
+ puts "+ f #{@base_dir}/spec/helpers/faastruby.rb".green
81
+ puts "+ f #{@base_dir}/spec/handler_spec.rb".green
82
+ puts "+ f #{@base_dir}/spec/spec_helper.rb".green
83
+ puts "+ f #{@base_dir}/Gemfile".green
84
+ puts "+ f #{@base_dir}/handler.rb".green
85
+ end
86
+
87
+ def write_yaml
88
+ write_file("#{@base_dir}/faastruby.yml", @yaml_content.to_yaml)
89
+ end
90
+
91
+ def bundle_install
92
+ spinner = spin("Installing gems...")
93
+ system("bundle install --gemfile=#{@base_dir}/Gemfile > /dev/null")
94
+ spinner.stop('Done!')
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,71 @@
1
+ module FaaStRuby
2
+ module Command
3
+ module Function
4
+ class RemoveFrom < FunctionBaseCommand
5
+ def initialize(args)
6
+ @args = args
7
+ @missing_args = []
8
+ FaaStRuby::CLI.error(@missing_args, color: nil) if missing_args.any?
9
+ @workspace_name = @args.shift
10
+ load_yaml
11
+ @function_name = @yaml_config['name']
12
+ FaaStRuby::Credentials.load_for(@workspace_name)
13
+ parse_options
14
+ end
15
+
16
+ def run
17
+ warning unless @options['force']
18
+ FaaStRuby::CLI.error("Cancelled") unless @options['force'] == 'y'
19
+ spinner = spin("Removing function from workspace '#{@workspace_name}'...")
20
+ workspace = FaaStRuby::Workspace.new(name: @workspace_name)
21
+ function = FaaStRuby::Function.new(name: @function_name, workspace: workspace)
22
+ function.destroy
23
+ if function.errors.any?
24
+ spinner.stop('Failed :(')
25
+ FaaStRuby::CLI.error(function.errors)
26
+ end
27
+ spinner.stop('Done!')
28
+ end
29
+
30
+ def self.help
31
+ "remove-from".blue + " WORKSPACE_NAME [-y, --yes]"
32
+ end
33
+
34
+ def usage
35
+ "Usage: faastruby #{self.class.help}"
36
+ end
37
+
38
+ private
39
+
40
+ def warning
41
+ print "WARNING: ".red
42
+ puts "This action will permanently remove the function '#{@function_name}' from the workspace '#{@workspace_name}'."
43
+ print "Are you sure? [y/N] "
44
+ @options['force'] = STDIN.gets.chomp
45
+ end
46
+
47
+ def parse_options
48
+ @options = {}
49
+ while @args.any?
50
+ option = @args.shift
51
+ case option
52
+ when '-y', '--yes'
53
+ @options['force'] = 'y'
54
+ else
55
+ FaaStRuby::CLI.error(["Unknown argument: #{option}".red, usage], color: nil)
56
+ end
57
+ end
58
+ end
59
+
60
+ def missing_args
61
+ if @args.empty?
62
+ @missing_args << "Missing argument: WORKSPACE_NAME".red
63
+ @missing_args << usage
64
+ end
65
+ FaaStRuby::CLI.error(["'#{@args.first}' is not a valid workspace name.".red, usage], color: nil) if @args.first =~ /^-.*/
66
+ @missing_args
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end