Class: Jets::Commands::Build

Inherits:
Object
  • Object
show all
Includes:
StackInfo
Defined in:
lib/jets/commands/build.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods included from StackInfo

#first_run?, #parent_stack_name, #s3_bucket, #stack_type

Methods included from AwsServices

#apigateway, #aws_lambda, #cfn, #dynamodb, #logs, #s3, #s3_resource, #sns, #sqs, #sts

Methods included from AwsServices::StackStatus

#lookup, #stack_exists?, #stack_in_progress?

Methods included from AwsServices::GlobalMemoist

included

Constructor Details

#initialize(options) ⇒ Build

Returns a new instance of Build.



7
8
9
# File 'lib/jets/commands/build.rb', line 7

def initialize(options)
  @options = options.dup
end

Class Method Details

.app_file?(path) ⇒ Boolean

Returns:

  • (Boolean)


198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/jets/commands/build.rb', line 198

def self.app_file?(path)
  return false unless File.extname(path) == ".rb"
  # Do not define lamda functions for the application_controller.rb or
  # application_job.rb
  excludes = %w[
    application_controller.rb
    application_job.rb
  ]
  return false if excludes.detect { |p| path.include?(p) }

  includes = %w[
    app/controllers
    app/jobs
    app/functions
    app/rules
  ]
  return true if includes.detect { |p| path.include?(p) }

  false
end

.app_filesObject

Crucial that the Dir.pwd is in the tmp_code because for because Jets.boot set ups autoload_paths and this is how project classes are loaded. TODO: rework code so that Dir.pwd does not have to be in tmp_code for build to work.



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/jets/commands/build.rb', line 110

def self.app_files
  paths = []
  expression = "#{Jets.root}/app/**/**/*.rb"
  Dir.glob(expression).each do |path|
    return false unless File.file?(path)
    next unless app_file?(path)
    next if concerns?(path)

    relative_path = path.sub("#{Jets.root}/", '')
    # Rids of the Jets.root at beginning
    paths << relative_path
  end
  paths += internal_app_files
  paths
end

.app_has_ruby?Boolean

Returns:

  • (Boolean)


151
152
153
154
155
156
157
158
# File 'lib/jets/commands/build.rb', line 151

def self.app_has_ruby?
  has_ruby = app_files.detect do |path|
    app_class = Jets::Klass.from_path(path)  # IE: PostsController, Jets::PublicController
    langs = app_class.tasks.map(&:lang)
    langs.include?(:ruby) && app_class != Jets::PreheatJob
  end
  !!has_ruby
end

.concerns?(path) ⇒ Boolean

Returns:

  • (Boolean)


219
220
221
# File 'lib/jets/commands/build.rb', line 219

def self.concerns?(path)
  path =~ %r{app/\w+/concerns/}
end

.internal_app_filesObject

Add internal Jets controllers if they are being used TODO: Interesting, this eventually just used to generate handlers and controllers only. Maybe rename to make that clear. The copying of other internal files like views is done in builders/code_builder.rb copy_internal_jets_code



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/jets/commands/build.rb', line 177

def self.internal_app_files
  paths = []
  controllers = File.expand_path("../../internal/app/controllers/jets", __FILE__)

  public_catchall = Jets::Router.has_controller?("Jets::PublicController")
  paths << "#{controllers}/public_controller.rb" if public_catchall

  rack_catchall = Jets::Router.has_controller?("Jets::RackController")
  paths << "#{controllers}/rack_controller.rb" if rack_catchall

  mailer_controller = Jets::Router.has_controller?("Jets::MailersController")
  paths << "#{controllers}/mailers_controller.rb" if mailer_controller

  if Jets.config.prewarm.enable
    jobs = File.expand_path("../../internal/app/jobs/jets", __FILE__)
    paths << "#{jobs}/preheat_job.rb"
  end

  paths
end

.poly_only?Boolean

Finds out of the app has polymorphic functions only and zero ruby functions. In this case, we can skip a lot of the ruby related building and speed up the deploy process.

Returns:

  • (Boolean)


147
148
149
# File 'lib/jets/commands/build.rb', line 147

def self.poly_only?
  !app_has_ruby? && !shared_has_ruby?
end

.shared_filesObject



130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/jets/commands/build.rb', line 130

def self.shared_files
  paths = []
  expression = "#{Jets.root}/app/**/**/*.rb"
  Dir.glob(expression).each do |path|
    return false unless File.file?(path)
    next unless path.include?("app/shared/resources")

    relative_path = path.sub("#{Jets.root}/", '')
    # Rids of the Jets.root at beginning
    paths << relative_path
  end
  paths
end

.shared_has_ruby?Boolean

Returns:

  • (Boolean)


160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/jets/commands/build.rb', line 160

def self.shared_has_ruby?
  has_ruby = false
  Jets::Stack.subclasses.each do |klass|
    klass.functions.each do |fun|
      if fun.lang == :ruby
        has_ruby = true
        break
      end
    end
  end
  has_ruby
end

.tmp_code(full_build_path = false) ⇒ Object



223
224
225
# File 'lib/jets/commands/build.rb', line 223

def self.tmp_code(full_build_path=false)
  full_build_path ? "#{Jets.build_root}/stage/code" : "stage/code"
end

Instance Method Details

#app_filesObject



102
103
104
# File 'lib/jets/commands/build.rb', line 102

def app_files
  self.class.app_files
end

#buildObject



21
22
23
24
# File 'lib/jets/commands/build.rb', line 21

def build
  build_code unless @options[:templates]
  build_templates
end

#build_all_templatesObject



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/jets/commands/build.rb', line 41

def build_all_templates
  # CloudFormation templates
  # 1. Shared templates - child templates needs them
  build_api_gateway_templates
  # 2. Child templates - parent template needs them
  build_app_child_templates
  # 2. Child templates - parent template needs them
  build_shared_resources_templates
  # 4. Finally parent template
  build_parent_template # must be called at the end
end

#build_api_gateway_templatesObject



57
58
59
60
# File 'lib/jets/commands/build.rb', line 57

def build_api_gateway_templates
  Jets::Cfn::Builders::ApiGatewayBuilder.new(@options).build
  Jets::Cfn::Builders::ApiDeploymentBuilder.new(@options).build
end

#build_app_child_templatesObject



62
63
64
65
66
# File 'lib/jets/commands/build.rb', line 62

def build_app_child_templates
  app_files.each do |path|
    build_child_template(path)
  end
end

#build_child_template(path) ⇒ Object

path: app/controllers/comments_controller.rb path: app/jobs/easy_job.rb



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/jets/commands/build.rb', line 76

def build_child_template(path)
  md = path.match(%r{app/(.*?)/}) # extract: controller, job or function
  process_class = md[1].classify
  builder_class = "Jets::Cfn::Builders::#{process_class}Builder".constantize

  # Examples:
  #   Jets::Cfn::Builders::ControllerBuilder.new(PostsController)
  #   Jets::Cfn::Builders::JobBuilder.new(EasyJob)
  #   Jets::Cfn::Builders::RuleBuilder.new(CheckRule)
  #   Jets::Cfn::Builders::FunctionBuilder.new(Hello)
  #   Jets::Cfn::Builders::FunctionBuilder.new(HelloFunction)
  app_class = Jets::Klass.from_path(path)
  builder = builder_class.new(app_class)
  unless Jets.poly_only? && app_class == Jets::PreheatJob
    builder.build
  end
end

#build_codeObject



26
27
28
# File 'lib/jets/commands/build.rb', line 26

def build_code
  Jets::Builders::CodeBuilder.new.build unless @options[:noop]
end

#build_minimal_templateObject



53
54
55
# File 'lib/jets/commands/build.rb', line 53

def build_minimal_template
  Jets::Cfn::Builders::ParentBuilder.new(@options).build
end

#build_parent_templateObject



94
95
96
# File 'lib/jets/commands/build.rb', line 94

def build_parent_template
  Jets::Cfn::Builders::ParentBuilder.new(@options).build
end

#build_shared_resources_templatesObject



68
69
70
71
72
# File 'lib/jets/commands/build.rb', line 68

def build_shared_resources_templates
  Jets::Stack.subclasses.each do |subclass|
    Jets::Cfn::Builders::SharedBuilder.new(subclass).build
  end
end

#build_templatesObject



30
31
32
33
34
35
# File 'lib/jets/commands/build.rb', line 30

def build_templates
  puts "Building CloudFormation templates."
  clean_templates
  build_minimal_template
  build_all_templates if full?
end

#clean_templatesObject



98
99
100
# File 'lib/jets/commands/build.rb', line 98

def clean_templates
  FileUtils.rm_rf("#{Jets.build_root}/templates")
end

#full?Boolean

Returns:

  • (Boolean)


37
38
39
# File 'lib/jets/commands/build.rb', line 37

def full?
  @options[:templates] || @options[:stack_type] == :full
end

#runObject



11
12
13
14
15
16
17
18
19
# File 'lib/jets/commands/build.rb', line 11

def run
  puts "Building project for Lambda..."

  return if @options[:noop]
  # run gets called from the CLI and does not have all the stack_options yet.
  # We compute it and change the options early here.
  @options.merge!(stack_type: stack_type, s3_bucket: s3_bucket)
  build
end

#shared_filesObject



126
127
128
# File 'lib/jets/commands/build.rb', line 126

def shared_files
  self.class.shared_files
end