lib/command/apply_template.rb in cpl-1.4.0 vs lib/command/apply_template.rb in cpl-2.2.0

- old
+ new

@@ -6,11 +6,12 @@ USAGE = "apply-template TEMPLATE [TEMPLATE] ... [TEMPLATE]" REQUIRES_ARGS = true OPTIONS = [ app_option(required: true), location_option, - skip_confirm_option + skip_confirm_option, + add_app_identity_option ].freeze DESCRIPTION = "Applies application-specific configs from templates" LONG_DESCRIPTION = <<~DESC - Applies application-specific configs from templates (e.g., for every review-app) - Publishes (creates or updates) those at Control Plane infrastructure @@ -34,73 +35,58 @@ ```sh # Applies single template. cpl apply-template redis -a $APP_NAME # Applies several templates (practically creating full app). - cpl apply-template gvc postgres redis rails -a $APP_NAME + cpl apply-template app postgres redis rails -a $APP_NAME ``` EX + VALIDATIONS = %w[config templates].freeze - def call # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity + def call # rubocop:disable Metrics/MethodLength + @template_parser = TemplateParser.new(config) + @names_to_filenames = config.args.to_h do |name| + [name, @template_parser.template_filename(name)] + end + ensure_templates! @created_items = [] @failed_templates = [] @skipped_templates = [] - @asked_for_confirmation = false - - pending_templates = templates.select do |template| - if template == "gvc" - confirm_app(template) - else - confirm_workload(template) - end + templates = @template_parser.parse(@names_to_filenames.values) + pending_templates = confirm_templates(templates) + add_app_identity_template(pending_templates) if config.options[:add_app_identity] + pending_templates.each do |template| + apply_template(template) end - progress.puts if @asked_for_confirmation - - @deprecated_variables = [] - - pending_templates.each do |template, filename| - step("Applying template '#{template}'", abort_on_error: false) do - items = apply_template(filename) - if items - items.each do |item| - report_success(item) - end - else - report_failure(template) - end - - $CHILD_STATUS.success? - end - end - - warn_deprecated_variables - print_created_items print_failed_templates print_skipped_templates - exit(1) if @failed_templates.any? + exit(ExitCode::ERROR_DEFAULT) if @failed_templates.any? end private - def templates - @templates ||= config.args.to_h do |template| - [template, "#{config.app_cpln_dir}/templates/#{template}.yml"] + def template_kind(template) + case template["kind"] + when "gvc" + "app" + else + template["kind"] end end def ensure_templates! - missing_templates = templates.reject { |_template, filename| File.exist?(filename) }.to_h + missing_templates = @names_to_filenames.reject { |_, filename| File.exist?(filename) } return if missing_templates.empty? - missing_templates_str = missing_templates.map do |template, filename| - " - #{template} (#{filename})" + missing_templates_str = missing_templates.map do |name, filename| + " - #{name} (#{filename})" end.join("\n") progress.puts("#{Shell.color('Missing templates:', :red)}\n#{missing_templates_str}\n\n") raise "Can't find templates above, please create them." end @@ -111,78 +97,82 @@ @asked_for_confirmation = true Shell.confirm(message) end def confirm_app(template) - app = cp.fetch_gvc + app = cp.fetch_gvc(template["name"]) return true unless app - confirmed = confirm_apply("App '#{config.app}' already exists, do you want to re-create it?") + confirmed = confirm_apply("App '#{template['name']}' already exists, do you want to re-create it?") return true if confirmed report_skipped(template) false end def confirm_workload(template) - workload = cp.fetch_workload(template) + workload = cp.fetch_workload(template["name"]) return true unless workload - confirmed = confirm_apply("Workload '#{template}' already exists, do you want to re-create it?") + confirmed = confirm_apply("Workload '#{template['name']}' already exists, do you want to re-create it?") return true if confirmed report_skipped(template) false end - def apply_template(filename) # rubocop:disable Metrics/MethodLength - data = File.read(filename) - .gsub("{{APP_ORG}}", config.org) - .gsub("{{APP_NAME}}", config.app) - .gsub("{{APP_LOCATION}}", config.location) - .gsub("{{APP_LOCATION_LINK}}", app_location_link) - .gsub("{{APP_IMAGE}}", latest_image) - .gsub("{{APP_IMAGE_LINK}}", app_image_link) - .gsub("{{APP_IDENTITY}}", app_identity) - .gsub("{{APP_IDENTITY_LINK}}", app_identity_link) - .gsub("{{APP_SECRETS}}", app_secrets) - .gsub("{{APP_SECRETS_POLICY}}", app_secrets_policy) + def confirm_templates(templates) # rubocop:disable Metrics/MethodLength + @asked_for_confirmation = false - find_deprecated_variables(data) + pending_templates = templates.select do |template| + case template["kind"] + when "gvc" + confirm_app(template) + when "workload" + confirm_workload(template) + else + true + end + end - # Kept for backwards compatibility - data = data - .gsub("APP_ORG", config.org) - .gsub("APP_GVC", config.app) - .gsub("APP_LOCATION", config.location) - .gsub("APP_IMAGE", latest_image) + progress.puts if @asked_for_confirmation - # Don't read in YAML.safe_load as that doesn't handle multiple documents - cp.apply_template(data) + pending_templates end - def new_variables + def add_app_identity_template(templates) + app_template_index = templates.index { |template| template["name"] == config.app } + app_identity_template_index = templates.index { |template| template["name"] == config.identity } + + return unless app_template_index && app_identity_template_index.nil? + + # Adding the identity template right after the app template is important since: + # a) we can't create the identity at the beginning because the app doesn't exist yet + # b) we also can't create it at the end because any workload templates associated with it will fail to apply + templates.insert(app_template_index + 1, build_app_identity_hash) + end + + def build_app_identity_hash { - "APP_ORG" => "{{APP_ORG}}", - "APP_GVC" => "{{APP_NAME}}", - "APP_LOCATION" => "{{APP_LOCATION}}", - "APP_IMAGE" => "{{APP_IMAGE}}" + "kind" => "identity", + "name" => config.identity } end - def find_deprecated_variables(data) - @deprecated_variables.push(*new_variables.keys.select { |old_key| data.include?(old_key) }) - @deprecated_variables = @deprecated_variables.uniq.sort - end + def apply_template(template) # rubocop:disable Metrics/MethodLength + step("Applying template for #{template_kind(template)} '#{template['name']}'", abort_on_error: false) do + items = cp.apply_hash(template) + unless items + report_failure(template) + next false + end - def warn_deprecated_variables - return unless @deprecated_variables.any? - - message = "Please replace these variables in the templates, " \ - "as support for them will be removed in a future major version bump:" - deprecated = @deprecated_variables.map { |old_key| " - #{old_key} -> #{new_variables[old_key]}" }.join("\n") - progress.puts("\n#{Shell.color("DEPRECATED: #{message}", :yellow)}\n#{deprecated}") + items.each do |item| + report_success(item) + end + true + end end def report_success(item) @created_items.push(item) end @@ -203,17 +193,17 @@ end def print_failed_templates return unless @failed_templates.any? - failed = @failed_templates.map { |template| " - #{template}" }.join("\n") + failed = @failed_templates.map { |template| " - [#{template_kind(template)}] #{template['name']}" }.join("\n") progress.puts("\n#{Shell.color('Failed to apply templates:', :red)}\n#{failed}") end def print_skipped_templates return unless @skipped_templates.any? - skipped = @skipped_templates.map { |template| " - #{template}" }.join("\n") + skipped = @skipped_templates.map { |template| " - [#{template_kind(template)}] #{template['name']}" }.join("\n") progress.puts("\n#{Shell.color('Skipped templates (already exist):', :blue)}\n#{skipped}") end end end