diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 8165b482..135e5b5f 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -12,614 +12,11 @@ Gemspec/OrderedDependencies: Exclude: - 'stack_master.gemspec' -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: outdent, indent -Layout/AccessModifierIndentation: - Exclude: - - 'lib/stack_master/parameter_resolvers/security_group.rb' - - 'lib/stack_master/parameter_resolvers/sso_group_id.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: with_first_argument, with_fixed_indentation -Layout/ArgumentAlignment: - Exclude: - - 'lib/stack_master/aws_driver/cloud_formation.rb' - - 'lib/stack_master/commands/drift.rb' - - 'lib/stack_master/config.rb' - - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/BlockEndNewline: - Exclude: - - 'spec/stack_master/change_set_spec.rb' - - 'spec/stack_master/commands/drift_spec.rb' - - 'spec/stack_master/paged_response_accumulator_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/security_group_finder_spec.rb' - - 'spec/stack_master/stack_differ_spec.rb' - - 'spec/stack_master/stack_events/fetcher_spec.rb' - - 'spec/stack_master/stack_events/streamer_spec.rb' - - 'spec/stack_master/template_compilers/json_spec.rb' - - 'spec/stack_master/template_compilers/yaml_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/ClosingHeredocIndentation: - Exclude: - - 'lib/stack_master/change_set.rb' - - 'spec/stack_master/parameter_validator_spec.rb' - - 'spec/stack_master/template_compilers/yaml_erb_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/ConditionPosition: - Exclude: - - 'lib/stack_master/parameter_resolvers/latest_container.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/ElseAlignment: - Exclude: - - 'lib/stack_master/prompter.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/test_driver/cloud_formation.rb' - - 'lib/stack_master/validator.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLineAfterGuardClause: - Exclude: - - 'lib/stack_master.rb' - - 'lib/stack_master/aws_driver/s3.rb' - - 'lib/stack_master/cli.rb' - - 'lib/stack_master/commands/apply.rb' - - 'lib/stack_master/config.rb' - - 'lib/stack_master/parameter_resolver.rb' - - 'lib/stack_master/parameter_resolvers/acm_certificate.rb' - - 'lib/stack_master/parameter_resolvers/env.rb' - - 'lib/stack_master/parameter_resolvers/one_password.rb' - - 'lib/stack_master/parameter_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/number_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/string_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator.rb' - - 'lib/stack_master/stack.rb' - - 'lib/stack_master/stack_definition.rb' - - 'lib/stack_master/stack_differ.rb' - - 'lib/stack_master/stack_events/streamer.rb' - - 'lib/stack_master/stack_status.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/template_utils.rb' - - 'lib/stack_master/utils.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLineAfterMagicComment: - Exclude: - - 'stack_master.gemspec' - -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLines: - Exclude: - - 'features/step_definitions/stack_steps.rb' - - 'spec/stack_master/parameter_resolvers/parameter_store_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: around, only_before -Layout/EmptyLinesAroundAccessModifier: - Exclude: - - 'lib/stack_master/config.rb' - - 'lib/stack_master/parameter_resolvers/sso_group_id.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLinesAroundArguments: - Exclude: - - 'lib/stack_master/config.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowAliasSyntax, AllowedMethods. -# AllowedMethods: alias_method, public, protected, private -Layout/EmptyLinesAroundAttributeAccessor: - Exclude: - - 'lib/stack_master.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: empty_lines, no_empty_lines -Layout/EmptyLinesAroundBlockBody: - Exclude: - - 'lib/stack_master/sparkle_formation/template_file.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample.rb' - - 'spec/stack_master/commands/delete_spec.rb' - - 'spec/stack_master/commands/init_spec.rb' - - 'spec/stack_master/commands/nag_spec.rb' - - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/commands/validate_spec.rb' - - 'spec/stack_master/parameter_loader_spec.rb' - - 'spec/stack_master/parameter_resolvers/env_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/parameter_resolvers/parameter_store_spec.rb' - - 'spec/stack_master/sns_topic_finder_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - - 'spec/stack_master/template_compilers/cfndsl_spec.rb' - - 'spec/stack_master/template_compilers/json_spec.rb' - - 'spec/stack_master/template_compilers/yaml_spec.rb' - - 'spec/stack_master/validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only -Layout/EmptyLinesAroundClassBody: - Exclude: - - 'lib/stack_master/aws_driver/cloud_formation.rb' - - 'lib/stack_master/commands/nag.rb' - - 'lib/stack_master/parameter_loader.rb' - - 'lib/stack_master/parameter_resolvers/env.rb' - - 'lib/stack_master/parameter_resolvers/parameter_store.rb' - - 'lib/stack_master/sns_topic_finder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/empty_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/number_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/state_builder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/string_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_builder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/EmptyLinesAroundMethodBody: - Exclude: - - 'lib/stack_master/commands/delete.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyleAlignWith, Severity. -# SupportedStylesAlignWith: keyword, variable, start_of_line -Layout/EndAlignment: - Exclude: - - 'lib/stack_master/prompter.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/test_driver/cloud_formation.rb' - - 'lib/stack_master/validator.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowForAlignment, AllowBeforeTrailingComments, ForceEqualSignAlignment. -Layout/ExtraSpacing: - Exclude: - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses -Layout/FirstArgumentIndentation: - Exclude: - - 'spec/stack_master/commands/drift_spec.rb' - - 'spec/stack_master/config_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_brackets -Layout/FirstArrayElementIndentation: - Exclude: - - 'lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb' - - 'spec/stack_master/cloudformation_interpolating_eruby_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/security_group_finder_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - - 'spec/stack_master/stack_definition_spec.rb' - - 'spec/stack_master/stack_spec.rb' - - 'spec/stack_master/utils_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: special_inside_parentheses, consistent, align_braces -Layout/FirstHashElementIndentation: - Exclude: - - 'features/step_definitions/asume_role_steps.rb' - - 'lib/stack_master/aws_driver/s3.rb' - - 'lib/stack_master/parameter_resolvers/latest_container.rb' - - 'lib/stack_master/parameter_resolvers/parameter_store.rb' - - 'lib/stack_master/role_assumer.rb' - - 'lib/stack_master/sso_group_id_finder.rb' - - 'spec/stack_master/aws_driver/s3_spec.rb' - - 'spec/stack_master/change_set_spec.rb' - - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/config_spec.rb' - - 'spec/stack_master/identity_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/role_assumer_spec.rb' - - 'spec/stack_master/sso_group_id_finder_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. -# SupportedHashRocketStyles: key, separator, table -# SupportedColonStyles: key, separator, table -# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit -Layout/HashAlignment: - Exclude: - - 'lib/stack_master/commands/drift.rb' - - 'lib/stack_master/config.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/sparkle_formation/template_file_spec.rb' - - 'spec/stack_master/stack_events/presenter_spec.rb' - - 'stack_master.gemspec' - -# This cop supports safe autocorrection (--autocorrect). -Layout/HeredocIndentation: - Exclude: - - 'lib/stack_master/change_set.rb' - - 'spec/integration/drift_spec.rb' - - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/sparkle_formation/template_file_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: normal, indented_internal_methods -Layout/IndentationConsistency: - Exclude: - - 'lib/stack_master/change_set.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/template_utils_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: Width, AllowedPatterns. -Layout/IndentationWidth: - Exclude: - - 'lib/stack_master/prompter.rb' - - 'lib/stack_master/sso_group_id_finder.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/test_driver/cloud_formation.rb' - - 'lib/stack_master/validator.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings. -# URISchemes: http, https -Layout/LineLength: - Exclude: - - 'features/step_definitions/parameter_store_steps.rb' - - 'features/step_definitions/stack_steps.rb' - - 'lib/stack_master/aws_driver/s3.rb' - - 'lib/stack_master/cli.rb' - - 'lib/stack_master/commands/apply.rb' - - 'lib/stack_master/commands/drift.rb' - - 'lib/stack_master/commands/init.rb' - - 'lib/stack_master/commands/resources.rb' - - 'lib/stack_master/commands/tidy.rb' - - 'lib/stack_master/identity.rb' - - 'lib/stack_master/parameter_loader.rb' - - 'lib/stack_master/parameter_resolver.rb' - - 'lib/stack_master/parameter_resolvers/acm_certificate.rb' - - 'lib/stack_master/parameter_resolvers/ejson.rb' - - 'lib/stack_master/parameter_resolvers/latest_container.rb' - - 'lib/stack_master/parameter_resolvers/one_password.rb' - - 'lib/stack_master/parameter_resolvers/stack_output.rb' - - 'lib/stack_master/security_group_finder.rb' - - 'lib/stack_master/sns_topic_finder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb' - - 'lib/stack_master/sso_group_id_finder.rb' - - 'lib/stack_master/stack.rb' - - 'lib/stack_master/stack_events/fetcher.rb' - - 'lib/stack_master/stack_events/presenter.rb' - - 'lib/stack_master/stack_events/streamer.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/template_utils.rb' - - 'lib/stack_master/test_driver/cloud_formation.rb' - - 'spec/stack_master/change_set_spec.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/commands/delete_spec.rb' - - 'spec/stack_master/commands/drift_spec.rb' - - 'spec/stack_master/commands/init_spec.rb' - - 'spec/stack_master/commands/resources_spec.rb' - - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/config_spec.rb' - - 'spec/stack_master/identity_spec.rb' - - 'spec/stack_master/paged_response_accumulator_spec.rb' - - 'spec/stack_master/parameter_loader_spec.rb' - - 'spec/stack_master/parameter_resolver_spec.rb' - - 'spec/stack_master/parameter_resolvers/ejson_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/parameter_resolvers/parameter_store_spec.rb' - - 'spec/stack_master/parameter_resolvers/stack_output_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb' - - 'spec/stack_master/stack_events/fetcher_spec.rb' - - 'spec/stack_master/stack_events/presenter_spec.rb' - - 'spec/stack_master/stack_events/streamer_spec.rb' - - 'spec/stack_master/stack_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - - 'spec/stack_master/template_compilers/cfndsl_spec.rb' - - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - - 'spec/stack_master/test_driver/cloud_formation_spec.rb' - - 'spec/stack_master/validator_spec.rb' - - 'stack_master.gemspec' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: symmetrical, new_line, same_line -Layout/MultilineArrayBraceLayout: - Exclude: - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/MultilineBlockLayout: - Exclude: - - 'spec/stack_master/change_set_spec.rb' - - 'spec/stack_master/commands/drift_spec.rb' - - 'spec/stack_master/paged_response_accumulator_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/security_group_finder_spec.rb' - - 'spec/stack_master/stack_differ_spec.rb' - - 'spec/stack_master/stack_events/fetcher_spec.rb' - - 'spec/stack_master/stack_events/streamer_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - - 'spec/stack_master/template_compilers/json_spec.rb' - - 'spec/stack_master/template_compilers/yaml_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: symmetrical, new_line, same_line -Layout/MultilineHashBraceLayout: - Exclude: - - 'spec/stack_master/aws_driver/s3_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: symmetrical, new_line, same_line -Layout/MultilineMethodCallBraceLayout: - Exclude: - - 'lib/stack_master/config.rb' - - 'spec/stack_master/commands/compile_spec.rb' - - 'spec/stack_master/commands/lint_spec.rb' - - 'spec/stack_master/commands/nag_spec.rb' - - 'spec/stack_master/stack_definition_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, IndentationWidth. -# SupportedStyles: aligned, indented, indented_relative_to_receiver -Layout/MultilineMethodCallIndentation: - Exclude: - - 'spec/stack_master/parameter_resolvers/env_spec.rb' - - 'spec/stack_master/parameter_resolvers/parameter_store_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/SpaceAfterColon: - Exclude: - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/SpaceAfterComma: - Exclude: - - 'lib/stack_master/aws_driver/s3.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/stack_events/presenter_spec.rb' - - 'spec/stack_master/stack_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: space, no_space -Layout/SpaceAroundEqualsInParameterDefault: - Exclude: - - 'lib/stack_master/cli.rb' - - 'lib/stack_master/parameter_resolvers/one_password.rb' - - 'lib/stack_master/template_utils.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/SpaceAroundKeyword: - Exclude: - - 'lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: AllowForAlignment, EnforcedStyleForExponentOperator, EnforcedStyleForRationalLiterals. -# SupportedStylesForExponentOperator: space, no_space -# SupportedStylesForRationalLiterals: space, no_space -Layout/SpaceAroundOperators: - Exclude: - - 'lib/stack_master/cli.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/template_file_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceBeforeBlockBraces: - Exclude: - - 'lib/stack_master/aws_driver/s3.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -Layout/SpaceBeforeComma: - Exclude: - - 'spec/stack_master/commands/apply_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: require_no_space, require_space -Layout/SpaceInLambdaLiteral: - Exclude: - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. -# SupportedStyles: space, no_space, compact -# SupportedStylesForEmptyBrackets: space, no_space -Layout/SpaceInsideArrayLiteralBrackets: - Exclude: - - 'lib/stack_master/stack_definition.rb' - - 'spec/stack_master/parameter_resolvers/stack_output_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. -# SupportedStyles: space, no_space -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceInsideBlockBraces: - Exclude: - - 'lib/stack_master/aws_driver/s3.rb' - - 'lib/stack_master/parameter_resolvers/ami_finder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/string_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb' - - 'spec/stack_master/cloudformation_template_eruby_spec.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/commands/init_spec.rb' - - 'spec/stack_master/commands/lint_spec.rb' - - 'spec/stack_master/parameter_resolvers/one_password_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. -# SupportedStyles: space, no_space, compact -# SupportedStylesForEmptyBraces: space, no_space -Layout/SpaceInsideHashLiteralBraces: - Exclude: - - 'lib/stack_master/commands/delete.rb' - - 'lib/stack_master/parameter_loader.rb' - - 'lib/stack_master/parameter_resolvers/ami_finder.rb' - - 'spec/stack_master/aws_driver/s3_spec.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/commands/delete_spec.rb' - - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/config_spec.rb' - - 'spec/stack_master/paged_response_accumulator_spec.rb' - - 'spec/stack_master/parameter_loader_spec.rb' - - 'spec/stack_master/parameter_resolvers/ami_finder_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_ami_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb' - - 'spec/stack_master/parameter_resolvers/stack_output_spec.rb' - - 'spec/stack_master/parameter_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - - 'spec/stack_master/sparkle_formation/template_file_spec.rb' - - 'spec/stack_master/sso_group_id_finder_spec.rb' - - 'spec/stack_master/stack_definition_spec.rb' - - 'spec/stack_master/stack_differ_spec.rb' - - 'spec/stack_master/stack_spec.rb' - - 'spec/stack_master/template_compiler_spec.rb' - - 'spec/stack_master/template_compilers/cfndsl_spec.rb' - - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - - 'spec/stack_master/template_compilers/yaml_spec.rb' - - 'spec/stack_master/test_driver/cloud_formation_spec.rb' - - 'spec/stack_master/utils_spec.rb' - - 'spec/stack_master/validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: space, compact, no_space -Layout/SpaceInsideParens: - Exclude: - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample-ctp.rb' - - 'spec/fixtures/templates/rb/cfndsl/sample.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/paged_response_accumulator_spec.rb' - - 'spec/stack_master/parameter_resolver_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: final_newline, final_blank_line -Layout/TrailingEmptyLines: - Exclude: - - 'lib/stack_master/resolver_array.rb' - - 'lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator.rb' - - 'lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb' - - 'lib/stack_master/sparkle_formation/template_file.rb' - - 'spec/stack_master/parameter_resolvers/sso_group_id_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb' - # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: AllowInHeredoc. Layout/TrailingWhitespace: Exclude: - - 'lib/stack_master/parameter_resolvers/one_password.rb' - - 'spec/stack_master/commands/lint_spec.rb' - 'spec/stack_master/commands/status_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/parameter_resolvers/parameter_store_spec.rb' - - 'spec/stack_master/resolver_array_spec.rb' # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: AllowSafeAssignment. @@ -791,6 +188,7 @@ Metrics/BlockLength: - 'spec/stack_master/commands/compile_spec.rb' - 'spec/stack_master/commands/delete_spec.rb' - 'spec/stack_master/commands/drift_spec.rb' + - 'spec/stack_master/commands/init_spec.rb' - 'spec/stack_master/commands/lint_spec.rb' - 'spec/stack_master/commands/nag_spec.rb' - 'spec/stack_master/commands/outputs_spec.rb' @@ -835,6 +233,7 @@ Metrics/BlockLength: - 'spec/stack_master/stack_spec.rb' - 'spec/stack_master/template_compiler_spec.rb' - 'spec/stack_master/template_compilers/cfndsl_spec.rb' + - 'spec/stack_master/template_compilers/json_spec.rb' - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - 'spec/stack_master/template_compilers/yaml_erb_spec.rb' - 'spec/stack_master/template_utils_spec.rb' @@ -871,6 +270,7 @@ Metrics/MethodLength: - 'lib/stack_master/commands/drift.rb' - 'lib/stack_master/commands/init.rb' - 'lib/stack_master/commands/lint.rb' + - 'lib/stack_master/commands/resources.rb' - 'lib/stack_master/commands/status.rb' - 'lib/stack_master/commands/tidy.rb' - 'lib/stack_master/config.rb' @@ -996,13 +396,6 @@ Style/AndOr: Exclude: - 'lib/stack_master/cli.rb' -# This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle. -# SupportedStyles: percent_q, bare_percent -Style/BarePercentLiterals: - Exclude: - - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - # This cop supports safe autocorrection (--autocorrect). # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods. # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces @@ -1030,13 +423,11 @@ Style/BlockDelimiters: - 'spec/stack_master/parameter_resolvers/stack_output_spec.rb' - 'spec/stack_master/security_group_finder_spec.rb' - 'spec/stack_master/sparkle_formation/template_file_spec.rb' - - 'spec/stack_master/sso_group_id_finder_spec.rb' - 'spec/stack_master/stack_differ_spec.rb' - 'spec/stack_master/stack_events/fetcher_spec.rb' - 'spec/stack_master/stack_events/streamer_spec.rb' - 'spec/stack_master/stack_spec.rb' - 'spec/stack_master/template_compiler_spec.rb' - - 'spec/stack_master/template_compilers/cfndsl_spec.rb' - 'spec/stack_master/template_compilers/json_spec.rb' - 'spec/stack_master/template_compilers/sparkle_formation_spec.rb' - 'spec/stack_master/template_compilers/yaml_spec.rb' @@ -1249,21 +640,13 @@ Style/HashSyntax: Style/IfUnlessModifier: Exclude: - 'bin/stack_master' - - 'lib/stack_master/aws_driver/s3.rb' - 'lib/stack_master/change_set.rb' - 'lib/stack_master/commands/apply.rb' - 'lib/stack_master/commands/drift.rb' - 'lib/stack_master/commands/events.rb' - - 'lib/stack_master/parameter_resolvers/acm_certificate.rb' - - 'lib/stack_master/parameter_resolvers/one_password.rb' - - 'lib/stack_master/security_group_finder.rb' - - 'lib/stack_master/sns_topic_finder.rb' - - 'lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb' - 'lib/stack_master/sparkle_formation/compile_time/value_builder.rb' - 'lib/stack_master/sparkle_formation/compile_time/value_validator.rb' - 'lib/stack_master/stack_differ.rb' - - 'lib/stack_master/template_compilers/sparkle_formation.rb' - - 'lib/stack_master/template_utils.rb' # This cop supports unsafe autocorrection (--autocorrect-all). # Configuration parameters: InverseMethods, InverseBlocks. @@ -1630,18 +1013,11 @@ Style/UnlessElse: - 'lib/stack_master/cli.rb' # This cop supports safe autocorrection (--autocorrect). -# Configuration parameters: EnforcedStyle, MinSize, WordRegex. +# Configuration parameters: WordRegex. # SupportedStyles: percent, brackets Style/WordArray: - Exclude: - - 'lib/stack_master/change_set.rb' - - 'lib/stack_master/commands/apply.rb' - - 'lib/stack_master/commands/drift.rb' - - 'spec/stack_master/commands/apply_spec.rb' - - 'spec/stack_master/config_spec.rb' - - 'spec/stack_master/parameter_resolvers/latest_container_spec.rb' - - 'spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb' - - 'spec/stack_master/test_driver/cloud_formation_spec.rb' + EnforcedStyle: percent + MinSize: 4 # This cop supports unsafe autocorrection (--autocorrect-all). Style/ZeroLengthPredicate: diff --git a/CHANGELOG.md b/CHANGELOG.md index 22315ca4..81529fff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,9 +13,11 @@ The format is based on [Keep a Changelog], and this project adheres to ### Changed - Always treat default parameter values from CloudFormation templates as strings. Avoids erroneous diffs being presented. ([#394]) +- Resolve layout issues identified by RuboCop ([#393]) [Unreleased]: https://github.com/envato/stack_master/compare/v2.17.0...HEAD [#394]: https://github.com/envato/stack_master/pull/394 +[#393]: https://github.com/envato/stack_master/pull/393 ## [2.17.0] - 2025-07-11 diff --git a/Rakefile b/Rakefile index 4fd0553e..161a82dd 100644 --- a/Rakefile +++ b/Rakefile @@ -14,7 +14,7 @@ end begin require 'cucumber/rake/task' Cucumber::Rake::Task.new(:features) do |t| - t.cucumber_opts = "features --format pretty" + t.cucumber_opts = %w[features --format pretty] end require 'rspec/core/rake_task' diff --git a/features/step_definitions/asume_role_steps.rb b/features/step_definitions/asume_role_steps.rb index 0e64f44c..7574c85d 100644 --- a/features/step_definitions/asume_role_steps.rb +++ b/features/step_definitions/asume_role_steps.rb @@ -1,7 +1,11 @@ Then(/^I expect the role "([^"]*)" is assumed in account "([^"]*)"$/) do |role, account| - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: "arn:aws:iam::#{account}:role/#{role}", - role_session_name: instance_of(String) - }) + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: "arn:aws:iam::#{account}:role/#{role}", + role_session_name: instance_of(String) + } + ) end diff --git a/features/step_definitions/parameter_store_steps.rb b/features/step_definitions/parameter_store_steps.rb index cc7e7323..1afc9224 100644 --- a/features/step_definitions/parameter_store_steps.rb +++ b/features/step_definitions/parameter_store_steps.rb @@ -1,4 +1,5 @@ -Given(/^(?:a|the) SSM parameter(?: named)? "([^"]*)" with value "([^"]*)" in region "([^"]*)"$/) do |parameter_name, parameter_value, parameter_region| +Given(/^(?:a|the)\ SSM\ parameter(?:\ named)?\ "([^"]*)" + \ with\ value\ "([^"]*)"\ in\ region\ "([^"]*)"$/x) do |parameter_name, parameter_value, parameter_region| Aws.config[:ssm] = { stub_responses: { get_parameter: { diff --git a/features/step_definitions/stack_steps.rb b/features/step_definitions/stack_steps.rb index d40540bb..7b535eb3 100644 --- a/features/step_definitions/stack_steps.rb +++ b/features/step_definitions/stack_steps.rb @@ -28,7 +28,6 @@ def extract_hash_from_kv_string(string) end end - Given(/^I stub the following stacks:$/) do |table| table.hashes.each do |row| row.symbolize_keys! @@ -62,7 +61,9 @@ def extract_hash_from_kv_string(string) end Given(/^I stub CloudFormation validate calls to fail validation with message "([^"]*)"$/) do |message| - allow(StackMaster.cloud_formation_driver).to receive(:validate_template).and_raise(Aws::CloudFormation::Errors::ValidationError.new('', message)) + allow(StackMaster.cloud_formation_driver) + .to receive(:validate_template) + .and_raise(Aws::CloudFormation::Errors::ValidationError.new('', message)) end Given(/^I stub the CloudFormation driver$/) do diff --git a/lib/stack_master.rb b/lib/stack_master.rb index 4234330d..5f94d8dc 100644 --- a/lib/stack_master.rb +++ b/lib/stack_master.rb @@ -140,6 +140,7 @@ def debug? def debug(message) return unless debug? + stderr.puts Rainbow("[DEBUG] #{message}").color(:green) end @@ -167,6 +168,7 @@ def skip_account_check? end attr_accessor :non_interactive_answer + @non_interactive_answer = 'y' def base_dir diff --git a/lib/stack_master/aws_driver/cloud_formation.rb b/lib/stack_master/aws_driver/cloud_formation.rb index 314d3927..2cc7b1b9 100644 --- a/lib/stack_master/aws_driver/cloud_formation.rb +++ b/lib/stack_master/aws_driver/cloud_formation.rb @@ -14,31 +14,33 @@ def set_region(value) end end - def_delegators :cf, :create_change_set, - :describe_change_set, - :execute_change_set, - :delete_change_set, - :delete_stack, - :cancel_update_stack, - :describe_stack_resources, - :get_template, - :get_stack_policy, - :set_stack_policy, - :describe_stack_events, - :update_stack, - :create_stack, - :validate_template, - :describe_stacks, - :detect_stack_drift, - :describe_stack_drift_detection_status, - :describe_stack_resource_drifts + def_delegators( + :cf, + :create_change_set, + :describe_change_set, + :execute_change_set, + :delete_change_set, + :delete_stack, + :cancel_update_stack, + :describe_stack_resources, + :get_template, + :get_stack_policy, + :set_stack_policy, + :describe_stack_events, + :update_stack, + :create_stack, + :validate_template, + :describe_stacks, + :detect_stack_drift, + :describe_stack_drift_detection_status, + :describe_stack_resource_drifts + ) private def cf @cf ||= Aws::CloudFormation::Client.new({ region: region, retry_limit: 10 }) end - end end end diff --git a/lib/stack_master/aws_driver/s3.rb b/lib/stack_master/aws_driver/s3.rb index a8f7c1dc..0f385b0d 100644 --- a/lib/stack_master/aws_driver/s3.rb +++ b/lib/stack_master/aws_driver/s3.rb @@ -11,16 +11,20 @@ def set_region(region) end def upload_files(bucket: nil, prefix: nil, region: nil, files: {}) - raise StackMaster::AwsDriver::S3ConfigurationError, 'A bucket must be specified in order to use S3' unless bucket + unless bucket + raise StackMaster::AwsDriver::S3ConfigurationError, 'A bucket must be specified in order to use S3' + end return if files.empty? s3 = new_s3_client(region: region) - current_objects = s3.list_objects({ - prefix: prefix, - bucket: bucket - }).map(&:contents).flatten.inject({}){|h,obj| + current_objects = s3.list_objects( + { + prefix: prefix, + bucket: bucket + } + ).map(&:contents).flatten.inject({}) { |h, obj| h.merge(obj.key => obj) } @@ -35,15 +39,18 @@ def upload_files(bucket: nil, prefix: nil, region: nil, files: {}) s3_md5 = current_objects[object_key] ? current_objects[object_key].etag.gsub("\"", '') : nil next if compiled_template_md5 == s3_md5 + s3_uri = "s3://#{bucket}/#{object_key}" StackMaster.stdout.print "- #{File.basename(path)} => #{s3_uri} " - s3.put_object({ - bucket: bucket, - key: object_key, - body: body, - metadata: { md5: compiled_template_md5 } - }) + s3.put_object( + { + bucket: bucket, + key: object_key, + body: body, + metadata: { md5: compiled_template_md5 } + } + ) StackMaster.stdout.puts "done." end end diff --git a/lib/stack_master/change_set.rb b/lib/stack_master/change_set.rb index 4201c6e7..3d06ab79 100644 --- a/lib/stack_master/change_set.rb +++ b/lib/stack_master/change_set.rb @@ -42,15 +42,15 @@ def initialize(describe_change_set_response) end def display(io) - io.puts <<-EOL + io.puts <<~EOL -======================================== -Proposed change set: -EOL + ======================================== + Proposed change set: + EOL @response.changes.each do |change| display_resource_change(io, change.resource_change) end -io.puts "========================================" + io.puts "========================================" end def failed? diff --git a/lib/stack_master/cli.rb b/lib/stack_master/cli.rb index 91015abb..9ba31e45 100644 --- a/lib/stack_master/cli.rb +++ b/lib/stack_master/cli.rb @@ -5,7 +5,7 @@ module StackMaster class CLI include Commander::Methods - def initialize(argv, stdin=STDIN, stdout=STDOUT, stderr=STDERR, kernel=Kernel) + def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel) @argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel Commander::Runner.instance_variable_set('@instance', Commander::Runner.new(argv)) StackMaster.stdout = @stdout @@ -41,9 +41,14 @@ def execute! command :apply do |c| c.syntax = 'stack_master apply [region_or_alias] [stack_name]' c.summary = 'Creates or updates a stack' - c.description = "Creates or updates a stack. Shows a diff of the proposed stack's template and parameters. Tails stack events until CloudFormation has completed." + c.description = "Creates or updates a stack. Shows a diff of the proposed stack's template and parameters. " \ + 'Tails stack events until CloudFormation has completed.' c.example 'update a stack named myapp-vpc in us-east-1', 'stack_master apply us-east-1 myapp-vpc' - c.option '--on-failure ACTION', String, "Action to take on CREATE_FAILURE. Valid Values: [ DO_NOTHING | ROLLBACK | DELETE ]. Default: ROLLBACK\nNote: You cannot use this option with Serverless Application Model (SAM) templates." + c.option '--on-failure ACTION', String, + 'Action to take on CREATE_FAILURE. ' \ + 'Valid Values: [ DO_NOTHING | ROLLBACK | DELETE ]. ' \ + "Default: ROLLBACK\n" \ + 'Note: You cannot use this option with Serverless Application Model (SAM) templates.' c.option '--yes-param PARAM_NAME', String, "Auto-approve stack updates when only parameter PARAM_NAME changes" c.action do |args, options| options.default config: default_config_file @@ -171,11 +176,13 @@ def execute! command :status do |c| c.syntax = 'stack_master status' c.summary = 'Check the current status stacks.' - c.description = 'Checks the status of all stacks defined in the stack_master.yml file. Warning this operation can be somewhat slow.' + c.description = 'Checks the status of all stacks defined in the stack_master.yml file. ' \ + 'Warning this operation can be somewhat slow.' c.example 'description', 'Check the status of all stack definitions' c.action do |args, options| options.default config: default_config_file say "Invalid arguments. stack_master status" and return unless args.size == 0 + config = load_config(options.config) StackMaster::Commands::Status.perform(config, nil, options) end @@ -184,11 +191,13 @@ def execute! command :tidy do |c| c.syntax = 'stack_master tidy' c.summary = 'Try to identify extra & missing files.' - c.description = 'Cross references stack_master.yml with the template and parameter directories to identify extra or missing files.' + c.description = 'Cross references stack_master.yml with the template ' \ + 'and parameter directories to identify extra or missing files.' c.example 'description', 'Check for missing or extra files' c.action do |args, options| options.default config: default_config_file say "Invalid arguments. stack_master tidy" and return unless args.size == 0 + config = load_config(options.config) StackMaster::Commands::Tidy.perform(config, nil, options) end @@ -269,11 +278,14 @@ def execute_stacks_command(command, args, options) success = false end stack_definitions = stack_definitions.select do |stack_definition| - running_in_allowed_account?(stack_definition.allowed_accounts) && StackStatus.new(config, stack_definition).changed? + running_in_allowed_account?(stack_definition.allowed_accounts) && + StackStatus.new(config, stack_definition).changed? end if options.changed stack_definitions.each do |stack_definition| StackMaster.cloud_formation_driver.set_region(stack_definition.region) - StackMaster.stdout.puts "Executing #{command.command_name} on #{stack_definition.stack_name} in #{stack_definition.region}" + StackMaster.stdout.puts( + "Executing #{command.command_name} on #{stack_definition.stack_name} in #{stack_definition.region}" + ) success = execute_if_allowed_account(stack_definition.allowed_accounts) do command.perform(config, stack_definition, options).success? end @@ -283,7 +295,7 @@ def execute_stacks_command(command, args, options) end def show_other_region_candidates(config, stack_name) - candidates = config.filter(region="", stack_name=stack_name) + candidates = config.filter(region = "", stack_name = stack_name) return if candidates.empty? StackMaster.stdout.puts "Stack name #{stack_name} exists in regions: #{candidates.map(&:region).join(', ')}" @@ -291,12 +303,15 @@ def show_other_region_candidates(config, stack_name) def execute_if_allowed_account(allowed_accounts, &block) raise ArgumentError, "Block required to execute this method" unless block_given? + if running_in_allowed_account?(allowed_accounts) block.call else account_text = "'#{identity.account}'" account_text << " (#{identity.account_aliases.join(', ')})" if identity.account_aliases.any? - StackMaster.stdout.puts "Account #{account_text} is not an allowed account. Allowed accounts are #{allowed_accounts}." + StackMaster.stdout.puts( + "Account #{account_text} is not an allowed account. Allowed accounts are #{allowed_accounts}." + ) false end end diff --git a/lib/stack_master/commands/apply.rb b/lib/stack_master/commands/apply.rb index 8339765c..ba106855 100644 --- a/lib/stack_master/commands/apply.rb +++ b/lib/stack_master/commands/apply.rb @@ -144,6 +144,7 @@ def ask_update_confirmation! def upload_files return unless use_s3? + s3.upload_files(**s3_options) end @@ -153,7 +154,8 @@ def template_method def template_value if use_s3? - s3.url(bucket: @s3_config['bucket'], prefix: @s3_config['prefix'], region: @s3_config['region'], template: @stack_definition.s3_template_file_name) + s3.url(bucket: @s3_config['bucket'], prefix: @s3_config['prefix'], region: @s3_config['region'], + template: @stack_definition.s3_template_file_name) else proposed_stack.template end @@ -161,6 +163,7 @@ def template_value def files_to_upload return {} unless use_s3? + @stack_definition.s3_files.tap do |files| files[@stack_definition.s3_template_file_name] = { path: @stack_definition.template_file_path, @@ -218,6 +221,7 @@ def set_stack_policy proposed_policy = proposed_stack.stack_policy_body # No need to reset a stack policy if it's nil or not changed return if proposed_policy.nil? || proposed_policy == current_policy + StackMaster.stdout.print 'Setting a stack policy...' cf.set_stack_policy( stack_name: stack_name, diff --git a/lib/stack_master/commands/delete.rb b/lib/stack_master/commands/delete.rb index 0fb2fcad..9e86006c 100644 --- a/lib/stack_master/commands/delete.rb +++ b/lib/stack_master/commands/delete.rb @@ -12,7 +12,6 @@ def initialize(region, stack_name, options) end def perform - return unless check_exists unless ask?("Really delete stack #{@stack_name} (y/n)? ") @@ -27,11 +26,11 @@ def perform private def delete_stack - cf.delete_stack({stack_name: @stack_name}) + cf.delete_stack({ stack_name: @stack_name }) end def check_exists - cf.describe_stacks({stack_name: @stack_name}) + cf.describe_stacks({ stack_name: @stack_name }) true rescue Aws::CloudFormation::Errors::ValidationError failed("Stack does not exist") diff --git a/lib/stack_master/commands/drift.rb b/lib/stack_master/commands/drift.rb index 6bd081b8..a3e9858c 100644 --- a/lib/stack_master/commands/drift.rb +++ b/lib/stack_master/commands/drift.rb @@ -15,7 +15,8 @@ def perform detect_stack_drift_result = cf.detect_stack_drift(stack_name: stack_name) drift_results = wait_for_drift_results(detect_stack_drift_result.stack_drift_detection_id) - puts colorize("Drift Status: #{drift_results.stack_drift_status}", stack_drift_status_color(drift_results.stack_drift_status)) + puts colorize("Drift Status: #{drift_results.stack_drift_status}", + stack_drift_status_color(drift_results.stack_drift_status)) return if drift_results.stack_drift_status == 'IN_SYNC' failed @@ -51,8 +52,10 @@ def display_drift(drift) end def display_resource_drift(drift) - diff = ::StackMaster::Diff.new(before: prettify_json(drift.expected_properties), - after: prettify_json(drift.actual_properties)) + diff = ::StackMaster::Diff.new( + before: prettify_json(drift.expected_properties), + after: prettify_json(drift.actual_properties) + ) diff.display_colorized_diff end diff --git a/lib/stack_master/commands/init.rb b/lib/stack_master/commands/init.rb index bc033a99..b82f75e4 100644 --- a/lib/stack_master/commands/init.rb +++ b/lib/stack_master/commands/init.rb @@ -28,11 +28,12 @@ def check_files @region_parameters_filename = File.join("parameters", @region, "#{@stack_name}.yml") if !@options.overwrite - [@stack_master_filename, @stack_json_filename, @parameters_filename, @region_parameters_filename].each do |filename| - if File.exist?(filename) - StackMaster.stderr.puts("Aborting: #{filename} already exists. Use --overwrite to force overwriting file.") - return false - end + [@stack_master_filename, @stack_json_filename, @parameters_filename, + @region_parameters_filename].each do |filename| + next unless File.exist?(filename) + + StackMaster.stderr.puts("Aborting: #{filename} already exists. Use --overwrite to force overwriting file.") + return false end end true diff --git a/lib/stack_master/commands/nag.rb b/lib/stack_master/commands/nag.rb index efed5406..ac682bbe 100644 --- a/lib/stack_master/commands/nag.rb +++ b/lib/stack_master/commands/nag.rb @@ -24,7 +24,6 @@ def stack_definition def proposed_stack @proposed_stack ||= Stack.generate(stack_definition, @config) end - end end end diff --git a/lib/stack_master/commands/resources.rb b/lib/stack_master/commands/resources.rb index 970d3ab1..037070c6 100644 --- a/lib/stack_master/commands/resources.rb +++ b/lib/stack_master/commands/resources.rb @@ -8,7 +8,15 @@ class Resources def perform if stack_resources - tp stack_resources, :logical_resource_id, :resource_type, :timestamp, :resource_status, :resource_status_reason, :description + tp( + stack_resources, + :logical_resource_id, + :resource_type, + :timestamp, + :resource_status, + :resource_status_reason, + :description + ) else failed("Stack doesn't exist") end diff --git a/lib/stack_master/commands/tidy.rb b/lib/stack_master/commands/tidy.rb index 24b440e8..078adf3a 100644 --- a/lib/stack_master/commands/tidy.rb +++ b/lib/stack_master/commands/tidy.rb @@ -19,7 +19,10 @@ def perform templates.delete(template) if !File.exist?(template) - StackMaster.stdout.puts "Stack \"#{stack_definition.stack_name}\" in \"#{stack_definition.region}\" missing template \"#{rel_path(template)}\"" + StackMaster.stdout.puts( + "Stack \"#{stack_definition.stack_name}\" in \"#{stack_definition.region}\" " \ + "missing template \"#{rel_path(template)}\"" + ) end end end diff --git a/lib/stack_master/config.rb b/lib/stack_master/config.rb index 14cbc05a..b4cbbbbc 100644 --- a/lib/stack_master/config.rb +++ b/lib/stack_master/config.rb @@ -14,14 +14,16 @@ def self.load!(config_file = 'stack_master.yml') raise ConfigParseError, "Unable to parse #{resolved_config_file}: #{error}" end - attr_accessor :stacks, - :base_dir, - :template_dir, - :parameters_dir, - :stack_defaults, - :region_defaults, - :region_aliases, - :template_compilers, + attr_accessor( + :stacks, + :base_dir, + :template_dir, + :parameters_dir, + :stack_defaults, + :region_defaults, + :region_aliases, + :template_compilers + ) def self.search_up_and_chdir(config_file) return config_file unless File.dirname(config_file) == "." @@ -52,6 +54,7 @@ def initialize(config, base_dir) @stacks = [] raise ConfigParseError.new("Stack defaults can't be undefined") if @stack_defaults.nil? + load_template_compilers(config) load_config end @@ -72,6 +75,7 @@ def unalias_region(region) end private + def load_template_compilers(config) @template_compilers = {} populate_template_compilers(config.fetch('template_compilers', {})) @@ -92,9 +96,9 @@ def default_template_compilers { rb: :sparkle_formation, json: :json, - yml: :yaml, + yml: :yaml, yaml: :yaml, - erb: :yaml_erb, + erb: :yaml_erb, } end @@ -123,7 +127,8 @@ def load_stacks(stacks) 'base_dir' => @base_dir, 'template_dir' => @template_dir, 'parameters_dir' => @parameters_dir, - 'additional_parameter_lookup_dirs' => @region_to_aliases[region]) + 'additional_parameter_lookup_dirs' => @region_to_aliases[region] + ) stack_attributes['allowed_accounts'] = attributes['allowed_accounts'] if attributes['allowed_accounts'] @stacks << StackDefinition.new(stack_attributes) end diff --git a/lib/stack_master/identity.rb b/lib/stack_master/identity.rb index 752021fc..7948ba3c 100644 --- a/lib/stack_master/identity.rb +++ b/lib/stack_master/identity.rb @@ -21,7 +21,8 @@ def account def account_aliases @aliases ||= iam.list_account_aliases.account_aliases rescue Aws::IAM::Errors::AccessDenied - raise MissingIamPermissionsError, 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases' + raise MissingIamPermissionsError, + 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases' end private diff --git a/lib/stack_master/parameter_loader.rb b/lib/stack_master/parameter_loader.rb index dbeadabb..4d62cb87 100644 --- a/lib/stack_master/parameter_loader.rb +++ b/lib/stack_master/parameter_loader.rb @@ -2,13 +2,12 @@ module StackMaster class ParameterLoader - COMPILE_TIME_PARAMETERS_KEY = 'compile_time_parameters' def self.load(parameter_files: [], parameters: {}) StackMaster.debug 'Searching for parameter files...' all_parameters = parameter_files.map { |file_name| load_parameters(file_name) } + [parameters] - all_parameters.reduce({template_parameters: {}, compile_time_parameters: {}}) do |hash, parameters| + all_parameters.reduce({ template_parameters: {}, compile_time_parameters: {} }) do |hash, parameters| template_parameters = create_template_parameters(parameters) compile_time_parameters = create_compile_time_parameters(parameters) @@ -32,7 +31,8 @@ def self.load_file(file_name) def self.create_template_parameters(parameters) parameters.deep_dup.tap do |parameters_clone| - parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY) || parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY.camelize) + parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY) || + parameters_clone.delete(COMPILE_TIME_PARAMETERS_KEY.camelize) end end @@ -43,6 +43,5 @@ def self.create_compile_time_parameters(parameters) def self.merge_and_camelize(hash, parameters) parameters.each { |key, value| hash[key.camelize] = value } end - end end diff --git a/lib/stack_master/parameter_resolver.rb b/lib/stack_master/parameter_resolver.rb index 33fdb480..8e316408 100644 --- a/lib/stack_master/parameter_resolver.rb +++ b/lib/stack_master/parameter_resolver.rb @@ -49,6 +49,7 @@ def resolve_parameter_value(key, parameter_value) return parameter_value.to_s if Numeric === parameter_value || parameter_value == true || parameter_value == false return resolve_array_parameter_values(key, parameter_value).join(',') if Array === parameter_value return parameter_value unless Hash === parameter_value + resolve_parameter_resolver_hash(key, parameter_value) rescue Aws::CloudFormation::Errors::ValidationError raise InvalidParameter, $!.message @@ -77,6 +78,7 @@ def assume_role_if_present(account, role, key) if account.nil? || role.nil? raise InvalidParameter, "Both 'account' and 'role' are required to assume role for parameter '#{key}'" end + role_assumer.assume_role(account, role) do yield end @@ -105,7 +107,8 @@ def resolver_class(class_name) begin @resolvers[class_name] = resolver_class_const(class_name).new(@config, @stack_definition) rescue NameError - raise ResolverNotFound, "Could not find parameter resolver called #{class_name}, please double check your configuration" + raise ResolverNotFound, + "Could not find parameter resolver called #{class_name}, please double check your configuration" end end end diff --git a/lib/stack_master/parameter_resolvers/acm_certificate.rb b/lib/stack_master/parameter_resolvers/acm_certificate.rb index d7e3c2e1..b2654eba 100644 --- a/lib/stack_master/parameter_resolvers/acm_certificate.rb +++ b/lib/stack_master/parameter_resolvers/acm_certificate.rb @@ -10,7 +10,10 @@ def initialize(config, stack_definition) def resolve(domain_name) cert_arn = find_cert_arn_by_domain_name(domain_name) - raise CertificateNotFound, "Could not find certificate #{domain_name} in #{@stack_definition.region}" unless cert_arn + unless cert_arn + raise CertificateNotFound, "Could not find certificate #{domain_name} in #{@stack_definition.region}" + end + cert_arn end diff --git a/lib/stack_master/parameter_resolvers/ami_finder.rb b/lib/stack_master/parameter_resolvers/ami_finder.rb index a8168a10..d079a3a6 100644 --- a/lib/stack_master/parameter_resolvers/ami_finder.rb +++ b/lib/stack_master/parameter_resolvers/ami_finder.rb @@ -15,7 +15,7 @@ def build_filters_from_string(value, prefix = nil) end def build_filters_from_hash(hash) - hash.map { |key, value| {name: key, values: Array(value.to_s)}} + hash.map { |key, value| { name: key, values: Array(value.to_s) } } end def find_latest_ami(filters, owners = ['self']) diff --git a/lib/stack_master/parameter_resolvers/ejson.rb b/lib/stack_master/parameter_resolvers/ejson.rb index 58009aee..26a01f76 100644 --- a/lib/stack_master/parameter_resolvers/ejson.rb +++ b/lib/stack_master/parameter_resolvers/ejson.rb @@ -23,16 +23,19 @@ def resolve(secret_key) def validate_ejson_file_specified if @stack_definition.ejson_file.nil? - raise ArgumentError, "No ejson_file defined for stack definition #{@stack_definition.stack_name} in #{@stack_definition.region}" + raise ArgumentError, 'No ejson_file defined for stack definition ' \ + "#{@stack_definition.stack_name} in #{@stack_definition.region}" end end def decrypt_ejson_file ejson_file_key = credentials_key @decrypted_ejson_files.fetch(ejson_file_key) do - @decrypted_ejson_files[ejson_file_key] = EJSONWrapper.decrypt(ejson_file_path, - use_kms: @stack_definition.ejson_file_kms, - region: ejson_file_region) + @decrypted_ejson_files[ejson_file_key] = EJSONWrapper.decrypt( + ejson_file_path, + use_kms: @stack_definition.ejson_file_kms, + region: ejson_file_region + ) end end diff --git a/lib/stack_master/parameter_resolvers/env.rb b/lib/stack_master/parameter_resolvers/env.rb index 035a8ab1..5a7ba93e 100644 --- a/lib/stack_master/parameter_resolvers/env.rb +++ b/lib/stack_master/parameter_resolvers/env.rb @@ -1,7 +1,6 @@ module StackMaster module ParameterResolvers class Env < Resolver - def initialize(config, stack_definition) @config = config @stack_definition = stack_definition @@ -10,9 +9,9 @@ def initialize(config, stack_definition) def resolve(value) environment_variable = ENV[value] raise ArgumentError, "The environment variable #{value} is not set" if environment_variable.nil? + environment_variable end - end end end diff --git a/lib/stack_master/parameter_resolvers/latest_container.rb b/lib/stack_master/parameter_resolvers/latest_container.rb index 0c86bc31..cf38aa18 100644 --- a/lib/stack_master/parameter_resolvers/latest_container.rb +++ b/lib/stack_master/parameter_resolvers/latest_container.rb @@ -28,7 +28,8 @@ def resolve(parameters) latest_image = images.first # aws_account_id.dkr.ecr.region.amazonaws.com/repository@sha256:digest - "#{latest_image.registry_id}.dkr.ecr.#{@region}.amazonaws.com/#{parameters['repository_name']}@#{latest_image.image_digest}" + "#{latest_image.registry_id}.dkr.ecr.#{@region}.amazonaws.com/#{parameters['repository_name']}@" \ + "#{latest_image.image_digest}" end private @@ -36,15 +37,16 @@ def resolve(parameters) def fetch_images(repository_name, registry_id, ecr) images = [] next_token = nil - while - resp = ecr.describe_images({ + while resp = ecr.describe_images( + { repository_name: repository_name, registry_id: registry_id, next_token: next_token, filter: { tag_status: "TAGGED", }, - }) + } + ) images += resp.image_details next_token = resp.next_token diff --git a/lib/stack_master/parameter_resolvers/one_password.rb b/lib/stack_master/parameter_resolvers/one_password.rb index 45d1a808..01629dc0 100644 --- a/lib/stack_master/parameter_resolvers/one_password.rb +++ b/lib/stack_master/parameter_resolvers/one_password.rb @@ -13,8 +13,12 @@ def initialize(config, stack_definition) @stack_definition = stack_definition end - def resolve(params={}) - raise OnePasswordNotAbleToAuthenticate, "1password requires the `OP_SESSION_` to be set, (remember to sign in?)" if ENV.keys.grep(/OP_SESSION_\w+$/).empty? + def resolve(params = {}) + if ENV.keys.grep(/OP_SESSION_\w+$/).empty? + raise OnePasswordNotAbleToAuthenticate, + "1password requires the `OP_SESSION_` to be set, (remember to sign in?)" + end + get_items(params) end @@ -40,7 +44,7 @@ def is_login_item?(data) end def password_item(data) - data.details.password + data.details.password end def login_item(data) diff --git a/lib/stack_master/parameter_resolvers/parameter_store.rb b/lib/stack_master/parameter_resolvers/parameter_store.rb index 443a3ff9..a7d0ee14 100644 --- a/lib/stack_master/parameter_resolvers/parameter_store.rb +++ b/lib/stack_master/parameter_resolvers/parameter_store.rb @@ -1,7 +1,6 @@ module StackMaster module ParameterResolvers class ParameterStore < Resolver - ParameterNotFound = Class.new(StandardError) def initialize(config, stack_definition) @@ -12,10 +11,7 @@ def initialize(config, stack_definition) def resolve(value) begin ssm = Aws::SSM::Client.new({ region: @stack_definition.region }) - resp = ssm.get_parameter({ - name: value, - with_decryption: true - }) + resp = ssm.get_parameter({ name: value, with_decryption: true }) rescue Aws::SSM::Errors::ParameterNotFound raise ParameterNotFound, "Unable to find #{value} in Parameter Store" end diff --git a/lib/stack_master/parameter_resolvers/security_group.rb b/lib/stack_master/parameter_resolvers/security_group.rb index da810c1c..c6a69d92 100644 --- a/lib/stack_master/parameter_resolvers/security_group.rb +++ b/lib/stack_master/parameter_resolvers/security_group.rb @@ -12,7 +12,7 @@ def resolve(value) security_group_finder.find(value) end - private + private def security_group_finder StackMaster::SecurityGroupFinder.new(@stack_definition.region) diff --git a/lib/stack_master/parameter_resolvers/sso_group_id.rb b/lib/stack_master/parameter_resolvers/sso_group_id.rb index 2f9ebc44..b1743e9a 100644 --- a/lib/stack_master/parameter_resolvers/sso_group_id.rb +++ b/lib/stack_master/parameter_resolvers/sso_group_id.rb @@ -12,7 +12,8 @@ def resolve(value) sso_group_id_finder.find(value) end - private + private + def sso_group_id_finder StackMaster::SsoGroupIdFinder.new() end diff --git a/lib/stack_master/parameter_resolvers/stack_output.rb b/lib/stack_master/parameter_resolvers/stack_output.rb index 4f4c6874..01379a2f 100644 --- a/lib/stack_master/parameter_resolvers/stack_output.rb +++ b/lib/stack_master/parameter_resolvers/stack_output.rb @@ -18,7 +18,9 @@ def resolve(value) region, stack_name, output_name = parse!(value) stack = find_stack(stack_name, region) if stack - output = stack.outputs.find { |stack_output| stack_output.output_key == output_name.camelize || stack_output.output_key == output_name } + output = stack.outputs.find do |stack_output| + stack_output.output_key == output_name.camelize || stack_output.output_key == output_name + end if output output.output_value else diff --git a/lib/stack_master/parameter_validator.rb b/lib/stack_master/parameter_validator.rb index b7b36b06..e6e0b8c2 100644 --- a/lib/stack_master/parameter_validator.rb +++ b/lib/stack_master/parameter_validator.rb @@ -9,6 +9,7 @@ def initialize(stack:, stack_definition:) def error_message return nil unless missing_parameters? + message = "Empty/blank parameters detected. Please provide values for these parameters:\n" missing_parameters.each do |parameter_name| message << " - #{parameter_name}\n" diff --git a/lib/stack_master/prompter.rb b/lib/stack_master/prompter.rb index 0e7780ec..b132ed62 100644 --- a/lib/stack_master/prompter.rb +++ b/lib/stack_master/prompter.rb @@ -4,18 +4,19 @@ module StackMaster module Prompter def ask?(question) StackMaster.stdout.print question - answer = if StackMaster.interactive? - if StackMaster.stdin.tty? && StackMaster.stdout.tty? - StackMaster.stdin.getch.chomp + answer = + if StackMaster.interactive? + if StackMaster.stdin.tty? && StackMaster.stdout.tty? + StackMaster.stdin.getch.chomp + else + StackMaster.stdout.puts + StackMaster.stdout.puts "STDOUT or STDIN was not a TTY. Defaulting to no. To force yes use -y" + 'n' + end else - StackMaster.stdout.puts - StackMaster.stdout.puts "STDOUT or STDIN was not a TTY. Defaulting to no. To force yes use -y" - 'n' + print StackMaster.non_interactive_answer + StackMaster.non_interactive_answer end - else - print StackMaster.non_interactive_answer - StackMaster.non_interactive_answer - end StackMaster.stdout.puts answer == 'y' end diff --git a/lib/stack_master/resolver_array.rb b/lib/stack_master/resolver_array.rb index 5d25a89e..c4e8f341 100644 --- a/lib/stack_master/resolver_array.rb +++ b/lib/stack_master/resolver_array.rb @@ -32,4 +32,3 @@ def self.array_resolver(options = {}) end end end - diff --git a/lib/stack_master/role_assumer.rb b/lib/stack_master/role_assumer.rb index f582cfbf..ab67804a 100644 --- a/lib/stack_master/role_assumer.rb +++ b/lib/stack_master/role_assumer.rb @@ -44,11 +44,13 @@ def with_temporary_cf_driver(&block) def assume_role_credentials(account, role) credentials_key = "#{account}:#{role}" @credentials.fetch(credentials_key) do - @credentials[credentials_key] = Aws::AssumeRoleCredentials.new({ - region: StackMaster.cloud_formation_driver.region, - role_arn: "arn:aws:iam::#{account}:role/#{role}", - role_session_name: "stack-master-role-assumer" - }) + @credentials[credentials_key] = Aws::AssumeRoleCredentials.new( + { + region: StackMaster.cloud_formation_driver.region, + role_arn: "arn:aws:iam::#{account}:role/#{role}", + role_session_name: "stack-master-role-assumer" + } + ) end end end diff --git a/lib/stack_master/security_group_finder.rb b/lib/stack_master/security_group_finder.rb index 237009a5..8398ca1d 100644 --- a/lib/stack_master/security_group_finder.rb +++ b/lib/stack_master/security_group_finder.rb @@ -8,7 +8,9 @@ def initialize(region) end def find(reference) - raise ArgumentError, 'Security group references must be non-empty strings' unless reference.is_a?(String) && !reference.empty? + unless reference.is_a?(String) && !reference.empty? + raise ArgumentError, 'Security group references must be non-empty strings' + end groups = @resource.security_groups({ filters: [ diff --git a/lib/stack_master/sns_topic_finder.rb b/lib/stack_master/sns_topic_finder.rb index 8de5b0ba..ee06d118 100644 --- a/lib/stack_master/sns_topic_finder.rb +++ b/lib/stack_master/sns_topic_finder.rb @@ -7,7 +7,9 @@ def initialize(region) end def find(reference) - raise ArgumentError, 'SNS topic references must be non-empty strings' unless reference.is_a?(String) && !reference.empty? + unless reference.is_a?(String) && !reference.empty? + raise ArgumentError, 'SNS topic references must be non-empty strings' + end topic = @resource.topics.detect { |t| topic_name_from_arn(t.arn) == reference } @@ -21,6 +23,5 @@ def find(reference) def topic_name_from_arn(arn) arn.split(":")[5] end - end end diff --git a/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb b/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb index 71b3543d..94bd673b 100644 --- a/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/allowed_pattern_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class AllowedPatternValidator < ValueValidator - KEY = :allowed_pattern def initialize(name, definition, parameter) @@ -17,6 +16,7 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition.key?(KEY) + invalid_values.empty? end @@ -28,7 +28,6 @@ def invalid_values def create_error "#{@name}:#{invalid_values} does not match #{KEY}:#{@definition[KEY]}" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb b/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb index e43cbf1d..7eb5f81a 100644 --- a/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/allowed_values_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class AllowedValuesValidator < ValueValidator - KEY = :allowed_values def initialize(name, definition, parameter) @@ -17,20 +16,20 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition.key?(KEY) + invalid_values.empty? end def invalid_values values = build_values(@definition, @parameter) values.reject do |value| - @definition[KEY].any? { |allowed_value| allowed_value.to_s == value.to_s} + @definition[KEY].any? { |allowed_value| allowed_value.to_s == value.to_s } end end def create_error "#{@name}:#{invalid_values} is not in #{KEY}:#{@definition[KEY]}" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb b/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb index baee00da..574e90ef 100644 --- a/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/definitions_validator.rb @@ -4,16 +4,17 @@ module StackMaster module SparkleFormation module CompileTime class DefinitionsValidator - VALID_TYPES = [:string, :number] def initialize(definitions) @definitions = definitions end def validate - @definitions.each do|name, definition| + @definitions.each do |name, definition| type = definition[:type] - raise ArgumentError.new "Unknown compile time parameter type: #{create_error(name, type)}" unless is_valid(type) + unless is_valid(type) + raise ArgumentError.new "Unknown compile time parameter type: #{create_error(name, type)}" + end end end @@ -26,8 +27,7 @@ def is_valid(type) def create_error(name, type) "#{name}:#{type} valid types are #{VALID_TYPES}" end - end end end -end \ No newline at end of file +end diff --git a/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb b/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb index a8c85721..1ca72644 100644 --- a/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/empty_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class EmptyValidator < ValueValidator - def initialize(name, definition, parameter) @name = name @definition = definition @@ -25,7 +24,6 @@ def has_invalid_values? def create_error "#{@name} cannot contain empty parameters:#{@parameter.inspect}" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb b/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb index b802704f..dd087a3d 100644 --- a/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/max_length_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class MaxLengthValidator < ValueValidator - KEY = :max_length def initialize(name, definition, parameter) @@ -18,6 +17,7 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :string return true unless @definition.key?(KEY) + invalid_values.empty? end @@ -29,7 +29,6 @@ def invalid_values def create_error "#{@name}:#{invalid_values} must not exceed #{KEY}:#{@definition[KEY]} characters" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb b/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb index bd8f3850..e5a813e5 100644 --- a/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/max_size_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class MaxSizeValidator < ValueValidator - KEY = :max_size def initialize(name, definition, parameter) @@ -18,6 +17,7 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :number return true unless @definition.key?(KEY) + invalid_values.empty? end @@ -29,7 +29,6 @@ def invalid_values def create_error "#{@name}:#{invalid_values} must not be greater than #{KEY}:#{@definition[KEY]}" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb b/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb index 2e980809..dc01c551 100644 --- a/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/min_length_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class MinLengthValidator < ValueValidator - KEY = :min_length def initialize(name, definition, parameter) @@ -18,18 +17,18 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :string return true unless @definition.key?(KEY) + invalid_values.empty? end def invalid_values values = build_values(@definition, @parameter) - values.select { |value| value.length < @definition[KEY].to_i} + values.select { |value| value.length < @definition[KEY].to_i } end def create_error "#{@name}:#{invalid_values} must be at least #{KEY}:#{@definition[KEY]} characters" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb b/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb index 8dcf6077..92d31fc1 100644 --- a/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/min_size_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class MinSizeValidator < ValueValidator - KEY = :min_size def initialize(name, definition, parameter) @@ -18,18 +17,18 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :number return true unless @definition.key?(KEY) + invalid_values.empty? end def invalid_values values = build_values(@definition, @parameter) - values.select { |value| value.to_f < @definition[KEY].to_f} + values.select { |value| value.to_f < @definition[KEY].to_f } end def create_error "#{@name}:#{invalid_values} must not be lesser than #{KEY}:#{@definition[KEY]}" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/number_validator.rb b/lib/stack_master/sparkle_formation/compile_time/number_validator.rb index 64a30b27..5bb3d5b4 100644 --- a/lib/stack_master/sparkle_formation/compile_time/number_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/number_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class NumberValidator < ValueValidator - def initialize(name, definition, parameter) @name = name @definition = definition @@ -15,6 +14,7 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :number + invalid_values.empty? end @@ -28,7 +28,6 @@ def invalid_values def create_error "#{@name}:#{invalid_values} are not Numbers" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb b/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb index 111bd35a..f973d9ed 100644 --- a/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/parameters_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class ParametersValidator - def initialize(definitions, parameters) @definitions = definitions @parameters = parameters diff --git a/lib/stack_master/sparkle_formation/compile_time/state_builder.rb b/lib/stack_master/sparkle_formation/compile_time/state_builder.rb index 5b235050..5402a54b 100644 --- a/lib/stack_master/sparkle_formation/compile_time/state_builder.rb +++ b/lib/stack_master/sparkle_formation/compile_time/state_builder.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class StateBuilder - def initialize(definitions, parameters) @definitions = definitions @parameters = parameters @@ -25,7 +24,6 @@ def build def create_value(definition, parameter) ValueBuilder.new(definition, parameter).build end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/string_validator.rb b/lib/stack_master/sparkle_formation/compile_time/string_validator.rb index 6d849274..47a6b83f 100644 --- a/lib/stack_master/sparkle_formation/compile_time/string_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/string_validator.rb @@ -4,7 +4,6 @@ module StackMaster module SparkleFormation module CompileTime class StringValidator < ValueValidator - def initialize(name, definition, parameter) @name = name @definition = definition @@ -15,18 +14,18 @@ def initialize(name, definition, parameter) def check_is_valid return true unless @definition[:type] == :string + invalid_values.empty? end def invalid_values values = build_values(@definition, @parameter) - values.reject { |value| value.is_a?(String)} + values.reject { |value| value.is_a?(String) } end def create_error "#{@name}:#{invalid_values} are not Strings" end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/value_builder.rb b/lib/stack_master/sparkle_formation/compile_time/value_builder.rb index 446eccd6..60eebe27 100644 --- a/lib/stack_master/sparkle_formation/compile_time/value_builder.rb +++ b/lib/stack_master/sparkle_formation/compile_time/value_builder.rb @@ -2,7 +2,6 @@ module StackMaster module SparkleFormation module CompileTime class ValueBuilder - def initialize(definition, parameter) @definition = definition @parameter = parameter @@ -33,7 +32,6 @@ def convert_strings_to_numbers @value = @value.map { |item| item.is_a?(String) ? item.to_f : item } if @value.is_a?(Array) end end - end end end diff --git a/lib/stack_master/sparkle_formation/compile_time/value_validator.rb b/lib/stack_master/sparkle_formation/compile_time/value_validator.rb index 0db1b984..a6e4f3f4 100644 --- a/lib/stack_master/sparkle_formation/compile_time/value_validator.rb +++ b/lib/stack_master/sparkle_formation/compile_time/value_validator.rb @@ -2,7 +2,6 @@ module StackMaster module SparkleFormation module CompileTime class ValueValidator - attr_reader :is_valid, :error def validate @@ -31,10 +30,10 @@ def convert_to_array(definition, parameter) if definition[:multiple] && parameter.is_a?(String) return parameter.split(',').map(&:strip) end + parameter.is_a?(Array) ? parameter : [parameter] end - end end end -end \ No newline at end of file +end diff --git a/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb b/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb index 1502434e..3a888861 100644 --- a/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb +++ b/lib/stack_master/sparkle_formation/compile_time/value_validator_factory.rb @@ -12,17 +12,16 @@ module StackMaster module SparkleFormation module CompileTime class ValueValidatorFactory - VALIDATORS_TYPES = [ - EmptyValidator, - StringValidator, - NumberValidator, - AllowedValuesValidator, - AllowedPatternValidator, - MaxLengthValidator, - MinLengthValidator, - MaxSizeValidator, - MinSizeValidator + EmptyValidator, + StringValidator, + NumberValidator, + AllowedValuesValidator, + AllowedPatternValidator, + MaxLengthValidator, + MinLengthValidator, + MaxSizeValidator, + MinSizeValidator ] def initialize(name, definition, parameter) @@ -32,10 +31,9 @@ def initialize(name, definition, parameter) end def build - VALIDATORS_TYPES.map { |validator| validator.new(@name, @definition, @parameter)} + VALIDATORS_TYPES.map { |validator| validator.new(@name, @definition, @parameter) } end - end end end -end \ No newline at end of file +end diff --git a/lib/stack_master/sparkle_formation/template_file.rb b/lib/stack_master/sparkle_formation/template_file.rb index f3ff7853..cb263ef6 100644 --- a/lib/stack_master/sparkle_formation/template_file.rb +++ b/lib/stack_master/sparkle_formation/template_file.rb @@ -17,7 +17,6 @@ def self.build(vars, prefix) value end end - end.new(vars, prefix) end @@ -64,4 +63,3 @@ def _user_data_file(file_name, vars = {}) SparkleFormation::SparkleAttribute::Aws.send(:include, StackMaster::SparkleFormation::UserDataFile) SparkleFormation::SparkleAttribute::Aws.send(:include, StackMaster::SparkleFormation::JoinedFile) - diff --git a/lib/stack_master/sso_group_id_finder.rb b/lib/stack_master/sso_group_id_finder.rb index c2a32434..9a453313 100644 --- a/lib/stack_master/sso_group_id_finder.rb +++ b/lib/stack_master/sso_group_id_finder.rb @@ -6,28 +6,31 @@ def find(reference) output_regex = %r{(?:(?[^:]+):)?(?[^:/]+)/(?.+)} if !reference.is_a?(String) || !(match = output_regex.match(reference)) - raise ArgumentError, 'Sso group lookup parameter must be in the form of [region:]identity-store-id/group_name' + raise ArgumentError, 'Sso group lookup parameter must be in the form of [region:]identity-store-id/group_name' end region = match[:region] || StackMaster.cloud_formation_driver.region client = Aws::IdentityStore::Client.new({ region: region }) begin - response = client.get_group_id({ - identity_store_id: match[:identity_store_id], - alternate_identifier: { - unique_attribute: { - attribute_path: 'displayName', - attribute_value: match[:group_name], + response = client.get_group_id( + { + identity_store_id: match[:identity_store_id], + alternate_identifier: { + unique_attribute: { + attribute_path: 'displayName', + attribute_value: match[:group_name], + }, }, - }, - }) + } + ) return response.group_id rescue Aws::IdentityStore::Errors::ServiceError => e - puts "Error calling GetGroupId: #{e.message}" + puts "Error calling GetGroupId: #{e.message}" end - raise SsoGroupNotFound, "No group with name #{match[:group_name]} found in identity store #{match[:identity_store_id]} in #{region}" + raise SsoGroupNotFound, + "No group with name #{match[:group_name]} found in identity store #{match[:identity_store_id]} in #{region}" end end end diff --git a/lib/stack_master/stack.rb b/lib/stack_master/stack.rb index 5922bcd3..88e2e580 100644 --- a/lib/stack_master/stack.rb +++ b/lib/stack_master/stack.rb @@ -17,10 +17,13 @@ class Stack include Utils::Initializable def template_default_parameters - TemplateUtils.template_hash(template).fetch('Parameters', {}).inject({}) do |result, (parameter_name, description)| - result[parameter_name] = description['Default']&.to_s - result - end + TemplateUtils + .template_hash(template) + .fetch('Parameters', {}) + .inject({}) do |result, (parameter_name, description)| + result[parameter_name] = description['Default']&.to_s + result + end end def parameters_with_defaults @@ -31,6 +34,7 @@ def self.find(region, stack_name) cf = StackMaster.cloud_formation_driver cf_stack = cf.describe_stacks({ stack_name: stack_name }).stacks.first return unless cf_stack + parameters = cf_stack.parameters.inject({}) do |params_hash, param_struct| params_hash[param_struct.parameter_key] = param_struct.parameter_value params_hash @@ -56,14 +60,27 @@ def self.find(region, stack_name) end def self.generate(stack_definition, config) - parameter_hash = ParameterLoader.load(parameter_files: stack_definition.all_parameter_files, parameters: stack_definition.parameters) + parameter_hash = ParameterLoader.load( + parameter_files: stack_definition.all_parameter_files, + parameters: stack_definition.parameters + ) template_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:template_parameters]) - compile_time_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:compile_time_parameters]) - template_body = TemplateCompiler.compile(config, stack_definition.compiler, stack_definition.template_dir, stack_definition.template, compile_time_parameters, stack_definition.compiler_options) + compile_time_parameters = ParameterResolver.resolve( + config, + stack_definition, + parameter_hash[:compile_time_parameters] + ) + template_body = TemplateCompiler.compile( + config, + stack_definition.compiler, + stack_definition.template_dir, + stack_definition.template, + compile_time_parameters, + stack_definition.compiler_options + ) template_format = TemplateUtils.identify_template_format(template_body) - stack_policy_body = if stack_definition.stack_policy_file_path - File.read(stack_definition.stack_policy_file_path) - end + stack_policy_body = + (File.read(stack_definition.stack_policy_file_path) if stack_definition.stack_policy_file_path) new(region: stack_definition.region, stack_name: stack_definition.stack_name, tags: stack_definition.tags, @@ -76,13 +93,26 @@ def self.generate(stack_definition, config) end def self.generate_without_parameters(stack_definition, config) - parameter_hash = ParameterLoader.load(parameter_files: stack_definition.all_parameter_files, parameters: stack_definition.parameters) - compile_time_parameters = ParameterResolver.resolve(config, stack_definition, parameter_hash[:compile_time_parameters]) - template_body = TemplateCompiler.compile(config, stack_definition.compiler, stack_definition.template_dir, stack_definition.template, compile_time_parameters, stack_definition.compiler_options) + parameter_hash = ParameterLoader.load( + parameter_files: stack_definition.all_parameter_files, + parameters: stack_definition.parameters + ) + compile_time_parameters = ParameterResolver.resolve( + config, + stack_definition, + parameter_hash[:compile_time_parameters] + ) + template_body = TemplateCompiler.compile( + config, + stack_definition.compiler, + stack_definition.template_dir, + stack_definition.template, + compile_time_parameters, + stack_definition.compiler_options + ) template_format = TemplateUtils.identify_template_format(template_body) - stack_policy_body = if stack_definition.stack_policy_file_path - File.read(stack_definition.stack_policy_file_path) - end + stack_policy_body = + (File.read(stack_definition.stack_policy_file_path) if stack_definition.stack_policy_file_path) new(region: stack_definition.region, stack_name: stack_definition.stack_name, tags: stack_definition.tags, @@ -96,6 +126,7 @@ def self.generate_without_parameters(stack_definition, config) def max_template_size(use_s3) return TemplateUtils::MAX_S3_TEMPLATE_SIZE if use_s3 + TemplateUtils::MAX_TEMPLATE_SIZE end diff --git a/lib/stack_master/stack_definition.rb b/lib/stack_master/stack_definition.rb index 939e0c4c..a71e8b96 100644 --- a/lib/stack_master/stack_definition.rb +++ b/lib/stack_master/stack_definition.rb @@ -65,6 +65,7 @@ def ==(other) def template_file_path return unless template + File.expand_path(template, template_dir) end @@ -85,6 +86,7 @@ def s3_files def s3_template_file_name return template if ['.json', '.yaml', '.yml'].include?(File.extname(template)) + Utils.change_extension(template, 'json') end @@ -101,7 +103,7 @@ def parameter_files_from_globs end def parameter_file_globs - [ default_parameter_glob, region_parameter_glob ] + additional_parameter_lookup_globs + [default_parameter_glob, region_parameter_glob] + additional_parameter_lookup_globs end def stack_policy_file_path diff --git a/lib/stack_master/stack_differ.rb b/lib/stack_master/stack_differ.rb index 488b6699..916f6edd 100644 --- a/lib/stack_master/stack_differ.rb +++ b/lib/stack_master/stack_differ.rb @@ -10,12 +10,14 @@ def initialize(proposed_stack, current_stack) def proposed_template return @proposed_stack.template_body unless @proposed_stack.template_format == :json + JSON.pretty_generate(JSON.parse(@proposed_stack.template_body)) + "\n" end def current_template return '' unless @current_stack return @current_stack.template_body unless @current_stack.template_format == :json + JSON.pretty_generate(TemplateUtils.template_hash(@current_stack.template_body)) + "\n" end @@ -81,8 +83,10 @@ def noecho_keys def single_param_update?(param_name) return false if param_name.blank? || @current_stack.blank? || body_different? + differences = Hashdiff.diff(@current_stack.parameters_with_defaults, @proposed_stack.parameters_with_defaults) return false if differences.count != 1 + diff = differences[0] diff[0] == "~" && diff[1] == param_name end diff --git a/lib/stack_master/stack_events/fetcher.rb b/lib/stack_master/stack_events/fetcher.rb index e0343838..471053ff 100644 --- a/lib/stack_master/stack_events/fetcher.rb +++ b/lib/stack_master/stack_events/fetcher.rb @@ -31,7 +31,9 @@ def filter_old_events(events) end def fetch_events - PagedResponseAccumulator.call(cf, :describe_stack_events, { stack_name: @stack_name }, :stack_events).stack_events + PagedResponseAccumulator + .call(cf, :describe_stack_events, { stack_name: @stack_name }, :stack_events) + .stack_events end end end diff --git a/lib/stack_master/stack_events/presenter.rb b/lib/stack_master/stack_events/presenter.rb index 0fe016f8..6d98981e 100644 --- a/lib/stack_master/stack_events/presenter.rb +++ b/lib/stack_master/stack_events/presenter.rb @@ -10,7 +10,12 @@ def initialize(io) end def print_event(event) - @io.puts Rainbow("#{event.timestamp.localtime} #{event.logical_resource_id} #{event.resource_type} #{event.resource_status} #{event.resource_status_reason}").color(event_colour(event)) + @io.puts( + Rainbow( + "#{event.timestamp.localtime} #{event.logical_resource_id} #{event.resource_type} " \ + "#{event.resource_status} #{event.resource_status_reason}" + ).color(event_colour(event)) + ) end def event_colour(event) diff --git a/lib/stack_master/stack_events/streamer.rb b/lib/stack_master/stack_events/streamer.rb index 200f82f6..0ddd5e9b 100644 --- a/lib/stack_master/stack_events/streamer.rb +++ b/lib/stack_master/stack_events/streamer.rb @@ -7,7 +7,8 @@ def self.stream(stack_name, region, **args, &block) new(stack_name, region, **args, &block).stream end - def initialize(stack_name, region, from: Time.now, break_on_finish_state: true, sleep_between_fetches: 1, io: nil, &block) + def initialize(stack_name, region, from: Time.now, break_on_finish_state: true, sleep_between_fetches: 1, + io: nil, &block) @stack_name = stack_name @region = region @block = block @@ -42,6 +43,7 @@ def unseen_events(events) [].tap do |unseen_events| events.each do |event| next if @seen_events.include?(event.event_id) + @seen_events << event.event_id unseen_events << event end diff --git a/lib/stack_master/stack_status.rb b/lib/stack_master/stack_status.rb index 64b57e8a..9b9bd470 100644 --- a/lib/stack_master/stack_status.rb +++ b/lib/stack_master/stack_status.rb @@ -39,6 +39,7 @@ def no_echo_params? def stack return @stack if defined?(@stack) + StackMaster.cloud_formation_driver.set_region(stack_definition.region) @stack = find_stack end diff --git a/lib/stack_master/template_compilers/sparkle_formation.rb b/lib/stack_master/template_compilers/sparkle_formation.rb index e4e932b2..334bd238 100644 --- a/lib/stack_master/template_compilers/sparkle_formation.rb +++ b/lib/stack_master/template_compilers/sparkle_formation.rb @@ -4,7 +4,6 @@ module StackMaster::TemplateCompilers class SparkleFormation - CompileTime = StackMaster::SparkleFormation::CompileTime def self.require_dependencies @@ -28,11 +27,12 @@ def self.compile(template_dir, template, compile_time_parameters, compiler_optio private def self.compile_sparkle_template(template_dir, template, compiler_options) - sparkle_path = if compiler_options['sparkle_path'] - File.expand_path(compiler_options['sparkle_path']) - else - template_dir - end + sparkle_path = + if compiler_options['sparkle_path'] + File.expand_path(compiler_options['sparkle_path']) + else + template_dir + end collection = ::SparkleFormation::SparkleCollection.new root_pack = ::SparkleFormation::Sparkle.new( @@ -48,7 +48,10 @@ def self.compile_sparkle_template(template_dir, template, compiler_options) end if compiler_options['sparkle_pack_template'] - raise ArgumentError.new("Template #{template.inspect} not found in any sparkle pack") unless collection.templates['aws'].include? template + unless collection.templates['aws'].include? template + raise ArgumentError.new("Template #{template.inspect} not found in any sparkle pack") + end + template_file_path = collection.templates['aws'][template].top['path'] else template_file_path = File.join(template_dir, template) diff --git a/lib/stack_master/template_utils.rb b/lib/stack_master/template_utils.rb index 1d0eaccd..37f5392d 100644 --- a/lib/stack_master/template_utils.rb +++ b/lib/stack_master/template_utils.rb @@ -16,8 +16,9 @@ def identify_template_format(template_body) end end - def template_hash(template_body=nil) + def template_hash(template_body = nil) return unless template_body + template_format = identify_template_format(template_body) case template_format when :json @@ -30,7 +31,10 @@ def template_hash(template_body=nil) def maybe_compressed_template_body(template_body) # Do not compress the template if it's not JSON because parsing YAML as a hash ignores # CloudFormation-specific tags such as !Ref - return template_body if template_body.size <= MAX_TEMPLATE_SIZE || identify_template_format(template_body) != :json + if template_body.size <= MAX_TEMPLATE_SIZE || identify_template_format(template_body) != :json + return template_body + end + JSON.dump(template_hash(template_body)) end end diff --git a/lib/stack_master/test_driver/cloud_formation.rb b/lib/stack_master/test_driver/cloud_formation.rb index 66cb0dbf..dd5cf8fd 100644 --- a/lib/stack_master/test_driver/cloud_formation.rb +++ b/lib/stack_master/test_driver/cloud_formation.rb @@ -99,11 +99,27 @@ def describe_change_set(options) change_set_id = options.fetch(:change_set_name) change_set = @change_sets.fetch(change_set_id) change_details = [ - OpenStruct.new(evaluation: 'Static', change_source: 'ResourceReference', target: OpenStruct.new(attribute: 'Properties', requires_recreation: 'Always', name: 'blah')) + OpenStruct.new( + evaluation: 'Static', + change_source: 'ResourceReference', + target: OpenStruct.new( + attribute: 'Properties', + requires_recreation: 'Always', + name: 'blah' + ) + ) ] - change = OpenStruct.new(action: 'Modify', replacement: 'True', scope: ['Properties'], details: change_details) + change = OpenStruct.new( + action: 'Modify', + replacement: 'True', + scope: ['Properties'], + details: change_details + ) changes = [ - OpenStruct.new(type: 'AWS::Resource', resource_change: change) + OpenStruct.new( + type: 'AWS::Resource', + resource_change: change + ) ] OpenStruct.new(change_set.merge(changes: changes, status: 'CREATE_COMPLETE')) end @@ -121,15 +137,16 @@ def delete_change_set(options) def describe_stacks(options = {}) stack_name = options[:stack_name] - stacks = if stack_name - if @stacks[stack_name] - [@stacks[stack_name]] + stacks = + if stack_name + if @stacks[stack_name] + [@stacks[stack_name]] + else + raise Aws::CloudFormation::Errors::ValidationError.new('', 'Stack does not exist') + end else - raise Aws::CloudFormation::Errors::ValidationError.new('', 'Stack does not exist') + @stacks.values end - else - @stacks.values - end OpenStruct.new(stacks: stacks, next_token: nil) end diff --git a/lib/stack_master/utils.rb b/lib/stack_master/utils.rb index 2149bee6..07173421 100644 --- a/lib/stack_master/utils.rb +++ b/lib/stack_master/utils.rb @@ -30,6 +30,7 @@ def hash_to_aws_parameters(params) def hash_to_aws_tags(tags) return [] if tags.nil? + tags.inject([]) do |aws_tags, (key, value)| aws_tags << { key: key, value: value } aws_tags diff --git a/lib/stack_master/validator.rb b/lib/stack_master/validator.rb index 7b9c4e26..07189644 100644 --- a/lib/stack_master/validator.rb +++ b/lib/stack_master/validator.rb @@ -35,11 +35,12 @@ def cf end def stack - @stack ||= if validate_template_parameters? - Stack.generate(@stack_definition, @config) - else - Stack.generate_without_parameters(@stack_definition, @config) - end + @stack ||= + if validate_template_parameters? + Stack.generate(@stack_definition, @config) + else + Stack.generate_without_parameters(@stack_definition, @config) + end end def parameter_validator diff --git a/spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb b/spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb index 4da68513..83d39b16 100644 --- a/spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb +++ b/spec/fixtures/templates/rb/cfndsl/sample-ctp-repeated.rb @@ -7,12 +7,11 @@ MaxLength 15 } - Output(:One,FnBase64( Ref("One"))) + Output(:One, FnBase64(Ref("One"))) EC2_Instance(:MyInstance) { DisableApiTermination external_parameters.fetch(:DisableApiTermination, "false") InstanceType external_parameters["InstanceType"] ImageId "ami-12345678" } - } diff --git a/spec/fixtures/templates/rb/cfndsl/sample-ctp.rb b/spec/fixtures/templates/rb/cfndsl/sample-ctp.rb index 89e63ba3..fa97240c 100644 --- a/spec/fixtures/templates/rb/cfndsl/sample-ctp.rb +++ b/spec/fixtures/templates/rb/cfndsl/sample-ctp.rb @@ -7,11 +7,10 @@ MaxLength 15 } - Output(:One,FnBase64( Ref("One"))) + Output(:One, FnBase64(Ref("One"))) EC2_Instance(:MyInstance) { InstanceType external_parameters["InstanceType"] ImageId "ami-12345678" } - } diff --git a/spec/fixtures/templates/rb/cfndsl/sample.rb b/spec/fixtures/templates/rb/cfndsl/sample.rb index adb409f9..f7664adb 100644 --- a/spec/fixtures/templates/rb/cfndsl/sample.rb +++ b/spec/fixtures/templates/rb/cfndsl/sample.rb @@ -7,10 +7,9 @@ MaxLength 15 } - Output(:One,FnBase64( Ref("One"))) + Output(:One, FnBase64(Ref("One"))) EC2_Instance(:MyInstance) { ImageId "ami-12345678" } - } diff --git a/spec/integration/drift_spec.rb b/spec/integration/drift_spec.rb index 24d0538c..170dcb03 100644 --- a/spec/integration/drift_spec.rb +++ b/spec/integration/drift_spec.rb @@ -6,10 +6,10 @@ before do allow(Aws::CloudFormation::Client).to receive(:new).and_return(cfn) write_file("stack_master.yml", <<~FILE) - stacks: - us-east-1: - myapp-web: - template: myapp_web.rb + stacks: + us-east-1: + myapp-web: + template: myapp_web.rb FILE end diff --git a/spec/stack_master/aws_driver/s3_spec.rb b/spec/stack_master/aws_driver/s3_spec.rb index 2d8c6528..bd64b8bb 100644 --- a/spec/stack_master/aws_driver/s3_spec.rb +++ b/spec/stack_master/aws_driver/s3_spec.rb @@ -30,11 +30,10 @@ bucket: 'bucket', region: 'region', prefix: 'prefix', - files: {'template' => { + files: { 'template' => { path: 'spec/fixtures/templates/myapp_vpc.json', body: 'file content' - } - } + } } } end @@ -58,11 +57,10 @@ { bucket: 'bucket', region: 'region', - files: {'template' => { + files: { 'template' => { :path => 'spec/fixtures/templates/myapp_vpc.json', :body => 'file content' - } - } + } } } end @@ -87,11 +85,10 @@ bucket: 'bucket', region: 'region', prefix: 'prefix', - files: {'template' => { + files: { 'template' => { :path => 'spec/fixtures/templates/myapp_vpc.json', :body => 'file content' - } - } + } } } end diff --git a/spec/stack_master/change_set_spec.rb b/spec/stack_master/change_set_spec.rb index 911a3eb6..ec918b78 100644 --- a/spec/stack_master/change_set_spec.rb +++ b/spec/stack_master/change_set_spec.rb @@ -21,22 +21,44 @@ context 'successful response' do before do - allow(cf).to receive(:describe_change_set).with({ change_set_name: 'id-1', next_token: nil }).and_return(double(next_token: nil, changes: [], :changes= => nil, :next_token= => nil, status: 'CREATE_COMPLETE')) + allow(cf) + .to receive(:describe_change_set) + .with({ change_set_name: 'id-1', next_token: nil }) + .and_return( + double( + next_token: nil, + changes: [], + :changes= => nil, + :next_token= => nil, + status: 'CREATE_COMPLETE' + ) + ) end it 'calls the create change set API with the addition of a name' do change_set = StackMaster::ChangeSet.create(stack_name: '123') - expect(cf).to have_received(:create_change_set).with({ - stack_name: '123', - change_set_name: change_set_name - }) + expect(cf) + .to have_received(:create_change_set) + .with({ stack_name: '123', change_set_name: change_set_name }) expect(change_set.failed?).to eq false end end context 'unsuccessful response' do before do - allow(cf).to receive(:describe_change_set).with({ change_set_name: 'id-1', next_token: nil }).and_return(double(next_token: nil, changes: [], :changes= => nil, :next_token= => nil, status: 'FAILED', status_reason: 'No changes')) + allow(cf) + .to receive(:describe_change_set) + .with({ change_set_name: 'id-1', next_token: nil }) + .and_return( + double( + next_token: nil, + changes: [], + :changes= => nil, + :next_token= => nil, + status: 'FAILED', + status_reason: 'No changes' + ) + ) end it 'is marked as failed' do @@ -49,10 +71,36 @@ describe '#display' do context 'a successful response' do let(:target) { OpenStruct.new(name: 'GroupDescription', attribute: 'Properties', requires_recreation: 'Always') } - let(:changes) { [ - OpenStruct.new(resource_change: OpenStruct.new(replacement: 'True', action: 'Modify', resource_type: 'EC2::Instance', logical_resource_id: '123', details: [OpenStruct.new(target: target, change_source: 'DirectModification', evaluation: 'Static', causing_entity: 'blah')])) - ] } - let(:cf_response) { double(next_token: nil, changes: changes, :changes= => nil, :next_token= => nil, status: 'FAILED', status_reason: 'No changes') } + let(:changes) { + [ + OpenStruct.new( + resource_change: OpenStruct.new( + replacement: 'True', + action: 'Modify', + resource_type: 'EC2::Instance', + logical_resource_id: '123', + details: [ + OpenStruct.new( + target: target, + change_source: 'DirectModification', + evaluation: 'Static', + causing_entity: 'blah' + ) + ] + ) + ) + ] + } + let(:cf_response) { + double( + next_token: nil, + changes: changes, + :changes= => nil, + :next_token= => nil, + status: 'FAILED', + status_reason: 'No changes' + ) + } let(:io) { StringIO.new } subject(:change_set) { StackMaster::ChangeSet.new(cf_response) } let(:message) { io.string } @@ -63,7 +111,8 @@ end it 'outputs detail data' do - expect(message).to include 'Properties.GroupDescription. Always requires recreation. Triggered by: DirectModification.blah' + expect(message) + .to include('Properties.GroupDescription. Always requires recreation. Triggered by: DirectModification.blah') end end end diff --git a/spec/stack_master/cloudformation_interpolating_eruby_spec.rb b/spec/stack_master/cloudformation_interpolating_eruby_spec.rb index a73028f7..e911dd2c 100644 --- a/spec/stack_master/cloudformation_interpolating_eruby_spec.rb +++ b/spec/stack_master/cloudformation_interpolating_eruby_spec.rb @@ -11,12 +11,14 @@ SHELL it 'returns an array of lines' do - expect(evaluate).to eq([ - "#!/bin/bash\n", - "\n", - "REGION=ap-southeast-2\n", - "echo $REGION\n", - ]) + expect(evaluate).to eq( + [ + "#!/bin/bash\n", + "\n", + "REGION=ap-southeast-2\n", + "echo $REGION\n", + ] + ) end end @@ -27,13 +29,15 @@ SHELL it 'includes CloudFormation objects in the array' do - expect(evaluate).to eq([ - "#!/bin/bash\n", - { 'Ref' => 'Param1' }, - ' ', - { 'Ref' => 'Param2' }, - "\n", - ]) + expect(evaluate).to eq( + [ + "#!/bin/bash\n", + { 'Ref' => 'Param1' }, + ' ', + { 'Ref' => 'Param2' }, + "\n", + ] + ) end end end @@ -50,12 +54,14 @@ SHELL it 'returns an array of lines' do - expect(evaluate_file).to eq([ - "#!/bin/bash\n", - "\n", - "REGION=ap-southeast-2\n", - "echo $REGION\n", - ]) + expect(evaluate_file).to eq( + [ + "#!/bin/bash\n", + "\n", + "REGION=ap-southeast-2\n", + "echo $REGION\n", + ] + ) end end end diff --git a/spec/stack_master/cloudformation_template_eruby_spec.rb b/spec/stack_master/cloudformation_template_eruby_spec.rb index 86ac349a..6dfd11ea 100644 --- a/spec/stack_master/cloudformation_template_eruby_spec.rb +++ b/spec/stack_master/cloudformation_template_eruby_spec.rb @@ -6,7 +6,7 @@ describe('.user_data_file') do context('given a template that loads a simple user data script file') do - let(:template) { <<~YAML} + let(:template) { <<~YAML } Resources: LaunchConfig: Type: 'AWS::AutoScaling::LaunchConfiguration' @@ -47,7 +47,7 @@ end context('given a template that loads a user data script file that includes another file') do - let(:template) { <<~YAML} + let(:template) { <<~YAML } Resources: LaunchConfig: Type: 'AWS::AutoScaling::LaunchConfiguration' @@ -92,7 +92,7 @@ describe('.include_file') do context('given a template that loads a lambda script') do - let(:template) { <<~YAML} + let(:template) { <<~YAML } Resources: Function: Type: 'AWS::Lambda::Function' diff --git a/spec/stack_master/commands/apply_spec.rb b/spec/stack_master/commands/apply_spec.rb index b8a98076..ef50fab0 100644 --- a/spec/stack_master/commands/apply_spec.rb +++ b/spec/stack_master/commands/apply_spec.rb @@ -10,7 +10,19 @@ let(:template_body) { '{}' } let(:template_format) { :json } let(:parameters) { { 'param_1' => 'hello' } } - let(:proposed_stack) { StackMaster::Stack.new(template_body: template_body, template_format: template_format, tags: { 'environment' => 'production' } , parameters: parameters, role_arn: role_arn, notification_arns: [notification_arn], stack_policy_body: stack_policy_body ) } + + let(:proposed_stack) do + StackMaster::Stack.new( + template_body: template_body, + template_format: template_format, + tags: { 'environment' => 'production' }, + parameters: parameters, + role_arn: role_arn, + notification_arns: [notification_arn], + stack_policy_body: stack_policy_body + ) + end + let(:stack_policy_body) { '{}' } let(:change_set) { double(display: true, failed?: false, id: '1') } let(:differ) { instance_double(StackMaster::StackDiffer, output_diff: nil, single_param_update?: false) } @@ -58,7 +70,10 @@ def apply it 'streams events' do Timecop.freeze(Time.local(1990)) do apply - expect(StackMaster::StackEvents::Streamer).to have_received(:stream).with(stack_name, region, io: STDOUT, from: Time.now) + + expect(StackMaster::StackEvents::Streamer) + .to have_received(:stream) + .with(stack_name, region, io: STDOUT, from: Time.now) end end @@ -183,12 +198,8 @@ def apply expect(cf).to have_received(:create_stack).with( stack_name: stack_name, template_body: proposed_stack.template_body, - parameters: [ - { parameter_key: 'param_1', parameter_value: 'hello' } - ], - tags: [ - { key: 'environment', value: 'production' } - ], + parameters: [{ parameter_key: 'param_1', parameter_value: 'hello' }], + tags: [{ key: 'environment', value: 'production' }], capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'], role_arn: role_arn, notification_arns: [notification_arn], @@ -219,7 +230,10 @@ def apply it 'streams events' do Timecop.freeze(Time.local(1990)) do apply - expect(StackMaster::StackEvents::Streamer).to have_received(:stream).with(stack_name, region, io: STDOUT, from: Time.now) + + expect(StackMaster::StackEvents::Streamer) + .to have_received(:stream) + .with(stack_name, region, io: STDOUT, from: Time.now) end end @@ -255,16 +269,19 @@ def apply end context 'stack is in review_in_progress' do - let(:stack) { StackMaster::Stack.new(stack_id: '1', stack_name: 'mistack', stack_status: 'REVIEW_IN_PROGRESS')} + let(:stack) { StackMaster::Stack.new(stack_id: '1', stack_name: 'mistack', stack_status: 'REVIEW_IN_PROGRESS') } it 'abort and fails with error' do - expect{ apply }.to output("Stack currently exists and is in REVIEW_IN_PROGRESS\nYou will need to delete the stack (mistack) before continuing\n").to_stderr + expect { apply }.to output(<<~OUTPUT).to_stderr + Stack currently exists and is in REVIEW_IN_PROGRESS + You will need to delete the stack (mistack) before continuing + OUTPUT end end context 'one or more parameters are empty' do let(:stack) { StackMaster::Stack.new(stack_id: '1', parameters: parameters) } - let(:parameters) { {'param1' => nil, 'param2' => nil, 'param3' => true} } + let(:parameters) { { 'param1' => nil, 'param2' => nil, 'param3' => true } } it "doesn't allow apply" do expect { apply }.to_not output(/Continue and apply the stack/).to_stdout diff --git a/spec/stack_master/commands/compile_spec.rb b/spec/stack_master/commands/compile_spec.rb index 54318149..425ba2aa 100644 --- a/spec/stack_master/commands/compile_spec.rb +++ b/spec/stack_master/commands/compile_spec.rb @@ -8,7 +8,8 @@ StackMaster::Stack.new( template_body: template_body, template_format: template_format, - parameters: parameters) + parameters: parameters + ) } let(:template_body) { '{}' } diff --git a/spec/stack_master/commands/delete_spec.rb b/spec/stack_master/commands/delete_spec.rb index 300ea90d..a2868f5f 100644 --- a/spec/stack_master/commands/delete_spec.rb +++ b/spec/stack_master/commands/delete_spec.rb @@ -1,5 +1,4 @@ RSpec.describe StackMaster::Commands::Delete do - subject(:delete) { described_class.new(stack_name, region, options) } let(:cf) { spy(Aws::CloudFormation::Client.new) } let(:region) { 'us-east-1' } @@ -16,13 +15,25 @@ describe "#perform" do context "The stack exists" do before do - allow(cf).to receive(:describe_stacks).and_return( - {stacks: [{ stack_id: "ABC", stack_name: stack_name, creation_time: Time.now, stack_status: 'UPDATE_COMPLETE', parameters: []}]} - ) + allow(cf) + .to receive(:describe_stacks) + .and_return( + { + stacks: [ + { + stack_id: "ABC", + stack_name: stack_name, + creation_time: Time.now, + stack_status: 'UPDATE_COMPLETE', + parameters: [] + } + ] + } + ) end it "deletes the stack and tails the events" do delete.perform - expect(cf).to have_received(:delete_stack).with({:stack_name => region}) + expect(cf).to have_received(:delete_stack).with({ :stack_name => region }) expect(StackMaster::StackEvents::Streamer).to have_received(:stream) end end @@ -39,5 +50,4 @@ end end end - end diff --git a/spec/stack_master/commands/drift_spec.rb b/spec/stack_master/commands/drift_spec.rb index 7f7ae704..724fbb55 100644 --- a/spec/stack_master/commands/drift_spec.rb +++ b/spec/stack_master/commands/drift_spec.rb @@ -6,35 +6,56 @@ subject(:drift) { described_class.new(config, stack_definition, options) } let(:stack_drift_detection_id) { 123 } - let(:detect_stack_drift_response) { Aws::CloudFormation::Types::DetectStackDriftOutput.new(stack_drift_detection_id: stack_drift_detection_id) } + let(:detect_stack_drift_response) { + Aws::CloudFormation::Types::DetectStackDriftOutput.new( + stack_drift_detection_id: stack_drift_detection_id + ) + } let(:stack_drift_status) { "IN_SYNC" } let(:describe_stack_drift_detection_status_response) { - Aws::CloudFormation::Types::DescribeStackDriftDetectionStatusOutput.new(stack_drift_detection_id: stack_drift_detection_id, - stack_drift_status: stack_drift_status, - detection_status: "DETECTION_COMPLETE") + Aws::CloudFormation::Types::DescribeStackDriftDetectionStatusOutput.new( + stack_drift_detection_id: stack_drift_detection_id, + stack_drift_status: stack_drift_status, + detection_status: "DETECTION_COMPLETE" + ) + } + let(:describe_stack_resource_drifts_response) { + Aws::CloudFormation::Types::DescribeStackResourceDriftsOutput.new( + stack_resource_drifts: stack_resource_drifts + ) + } + let(:property_difference) { + Aws::CloudFormation::Types::PropertyDifference.new( + difference_type: 'ADD', + property_path: '/SecurityGroupIngress/2' + ) + } + let(:stack_resource_drifts) { + [ + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: "IN_SYNC", + resource_type: "AWS::EC2::SecurityGroup", + logical_resource_id: "SecurityGroup", + physical_resource_id: "sg-123456", + property_differences: [property_difference] + ) + ] } - let(:describe_stack_resource_drifts_response) { Aws::CloudFormation::Types::DescribeStackResourceDriftsOutput.new(stack_resource_drifts: stack_resource_drifts) } - let(:property_difference) { Aws::CloudFormation::Types::PropertyDifference.new( - difference_type: 'ADD', - property_path: '/SecurityGroupIngress/2' - ) } - let(:stack_resource_drifts) { [ - Aws::CloudFormation::Types::StackResourceDrift.new(stack_resource_drift_status: "IN_SYNC", - resource_type: "AWS::EC2::SecurityGroup", - logical_resource_id: "SecurityGroup", - physical_resource_id: "sg-123456", - property_differences: [ - property_difference - ]) - ] } before do options.timeout = 10 - allow(StackMaster).to receive(:cloud_formation_driver).and_return(cf) - allow(cf).to receive(:detect_stack_drift).and_return(detect_stack_drift_response) - - allow(cf).to receive(:describe_stack_drift_detection_status).and_return(describe_stack_drift_detection_status_response) - allow(cf).to receive(:describe_stack_resource_drifts).and_return(describe_stack_resource_drifts_response) + allow(StackMaster) + .to receive(:cloud_formation_driver) + .and_return(cf) + allow(cf) + .to receive(:detect_stack_drift) + .and_return(detect_stack_drift_response) + allow(cf) + .to receive(:describe_stack_drift_detection_status) + .and_return(describe_stack_drift_detection_status_response) + allow(cf) + .to receive(:describe_stack_resource_drifts) + .and_return(describe_stack_resource_drifts_response) stub_const('StackMaster::Commands::Drift::SLEEP_SECONDS', 0) end @@ -53,25 +74,33 @@ let(:stack_drift_status) { 'DRIFTED' } let(:expected_properties) { '{"CidrIp":"1.2.3.4/0","FromPort":80,"IpProtocol":"tcp","ToPort":80}' } let(:actual_properties) { '{"CidrIp":"5.6.7.8/0","FromPort":80,"IpProtocol":"tcp","ToPort":80}' } - let(:stack_resource_drifts) { [ - Aws::CloudFormation::Types::StackResourceDrift.new(stack_resource_drift_status: "DELETED", - resource_type: "AWS::EC2::SecurityGroup", - logical_resource_id: "SecurityGroup1", - physical_resource_id: "sg-123456", - property_differences: [property_difference]), - Aws::CloudFormation::Types::StackResourceDrift.new(stack_resource_drift_status: "MODIFIED", - resource_type: "AWS::EC2::SecurityGroup", - logical_resource_id: "SecurityGroup2", - physical_resource_id: "sg-789012", - expected_properties: expected_properties, - actual_properties: actual_properties, - property_differences: [property_difference]), - Aws::CloudFormation::Types::StackResourceDrift.new(stack_resource_drift_status: "IN_SYNC", - resource_type: "AWS::EC2::SecurityGroup", - logical_resource_id: "SecurityGroup3", - physical_resource_id: "sg-345678", - property_differences: [property_difference]) - ] } + let(:stack_resource_drifts) { + [ + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: "DELETED", + resource_type: "AWS::EC2::SecurityGroup", + logical_resource_id: "SecurityGroup1", + physical_resource_id: "sg-123456", + property_differences: [property_difference] + ), + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: "MODIFIED", + resource_type: "AWS::EC2::SecurityGroup", + logical_resource_id: "SecurityGroup2", + physical_resource_id: "sg-789012", + expected_properties: expected_properties, + actual_properties: actual_properties, + property_differences: [property_difference] + ), + Aws::CloudFormation::Types::StackResourceDrift.new( + stack_resource_drift_status: "IN_SYNC", + resource_type: "AWS::EC2::SecurityGroup", + logical_resource_id: "SecurityGroup3", + physical_resource_id: "sg-345678", + property_differences: [property_difference] + ) + ] + } it 'outputs drift status' do expect { drift.perform }.to output(/Drift Status: DRIFTED/).to_stdout diff --git a/spec/stack_master/commands/init_spec.rb b/spec/stack_master/commands/init_spec.rb index 4217bfef..6b034527 100644 --- a/spec/stack_master/commands/init_spec.rb +++ b/spec/stack_master/commands/init_spec.rb @@ -1,18 +1,64 @@ RSpec.describe StackMaster::Commands::Init do - subject(:init_command) { described_class.new(options, region, stack_name) } let(:region) { "us-east-1" } let(:stack_name) { "test-stack" } - let(:options) { double(overwrite: false)} + let(:options) { double(overwrite: false) } describe "#perform" do it "creates all the expected files" do - expect(IO).to receive(:write).with("stack_master.yml", "stacks:\n us-east-1:\n test-stack:\n template: test-stack.json\n tags:\n environment: production\n") - expect(IO).to receive(:write).with("parameters/test-stack.yml", "# Add parameters here:\n# param1: value1\n# param2: value2\n") - expect(IO).to receive(:write).with("parameters/us-east-1/test-stack.yml", "# Add parameters here:\n# param1: value1\n# param2: value2\n") - expect(IO).to receive(:write).with("templates/test-stack.json", "{\n \"AWSTemplateFormatVersion\" : \"2010-09-09\",\n \"Description\" : \"Cloudformation stack for test-stack\",\n\n \"Parameters\" : {\n \"InstanceType\" : {\n \"Description\" : \"EC2 instance type\",\n \"Type\" : \"String\"\n }\n },\n\n \"Mappings\" : {\n },\n\n \"Resources\" : {\n },\n\n \"Outputs\" : {\n }\n}\n") + expect(IO) + .to receive(:write) + .with("stack_master.yml", <<~YAML) + stacks: + us-east-1: + test-stack: + template: test-stack.json + tags: + environment: production + YAML + + expect(IO) + .to receive(:write) + .with("parameters/test-stack.yml", <<~YAML) + # Add parameters here: + # param1: value1 + # param2: value2 + YAML + + expect(IO) + .to receive(:write) + .with("parameters/us-east-1/test-stack.yml", <<~YAML) + # Add parameters here: + # param1: value1 + # param2: value2 + YAML + + expect(IO) + .to receive(:write) + .with("templates/test-stack.json", <<~JSON) + { + "AWSTemplateFormatVersion" : "2010-09-09", + "Description" : "Cloudformation stack for test-stack", + + "Parameters" : { + "InstanceType" : { + "Description" : "EC2 instance type", + "Type" : "String" + } + }, + + "Mappings" : { + }, + + "Resources" : { + }, + + "Outputs" : { + } + } + JSON + init_command.perform() end end - end diff --git a/spec/stack_master/commands/lint_spec.rb b/spec/stack_master/commands/lint_spec.rb index e261fe00..399f7f0a 100644 --- a/spec/stack_master/commands/lint_spec.rb +++ b/spec/stack_master/commands/lint_spec.rb @@ -8,7 +8,8 @@ StackMaster::Stack.new( template_body: template_body, template_format: template_format, - parameters: parameters) + parameters: parameters + ) } let(:tempfile) { double(:tempfile) } let(:path) { double(:path) } @@ -17,7 +18,7 @@ allow(StackMaster::Stack).to receive(:generate).with(stack_definition, config).and_return(proposed_stack) end - def run + def run described_class.perform(config, stack_definition) end @@ -49,7 +50,7 @@ def run context "when cfn-lint is missing" do let(:template_body) { '' } - let(:template_format) { :json} + let(:template_format) { :json } it 'outputs a warning' do expect_any_instance_of(described_class).to receive(:system).once.with('cfn-lint', '--version').and_return(nil) diff --git a/spec/stack_master/commands/nag_spec.rb b/spec/stack_master/commands/nag_spec.rb index 2e6c855d..a7854bc5 100644 --- a/spec/stack_master/commands/nag_spec.rb +++ b/spec/stack_master/commands/nag_spec.rb @@ -8,7 +8,8 @@ StackMaster::Stack.new( template_body: template_body, template_format: template_format, - parameters: parameters) + parameters: parameters + ) } let(:tempfile) { double(Tempfile) } let(:path) { double(String) } @@ -62,5 +63,4 @@ def run expect(result.success?).to eq false end end - end diff --git a/spec/stack_master/commands/resources_spec.rb b/spec/stack_master/commands/resources_spec.rb index c8d3454d..dfc9f2e3 100644 --- a/spec/stack_master/commands/resources_spec.rb +++ b/spec/stack_master/commands/resources_spec.rb @@ -37,7 +37,8 @@ context 'given the stack does not exist' do before do - allow(cf).to receive(:describe_stack_resources).and_raise(Aws::CloudFormation::Errors::ValidationError.new('x', 'y')) + allow(cf).to receive(:describe_stack_resources).and_raise(Aws::CloudFormation::Errors::ValidationError.new('x', + 'y')) end specify 'the command is not successful' do diff --git a/spec/stack_master/commands/status_spec.rb b/spec/stack_master/commands/status_spec.rb index f347b339..3268ba43 100644 --- a/spec/stack_master/commands/status_spec.rb +++ b/spec/stack_master/commands/status_spec.rb @@ -2,8 +2,21 @@ subject(:status) { described_class.new(config, Commander::Command::Options.new, false) } let(:config) { instance_double(StackMaster::Config, stacks: stacks) } let(:stacks) { [stack_definition_1, stack_definition_2] } - let(:stack_definition_1) { double(:stack_definition_1, region: 'us-east-1', stack_name: 'stack1', allowed_accounts: []) } - let(:stack_definition_2) { double(:stack_definition_2, region: 'us-east-1', stack_name: 'stack2', stack_status: 'CREATE_COMPLETE', allowed_accounts: []) } + + let(:stack_definition_1) do + double(:stack_definition_1, region: 'us-east-1', stack_name: 'stack1', allowed_accounts: []) + end + + let(:stack_definition_2) do + double( + :stack_definition_2, + region: 'us-east-1', + stack_name: 'stack2', + stack_status: 'CREATE_COMPLETE', + allowed_accounts: [] + ) + end + let(:cf) { Aws::CloudFormation::Client.new(region: 'us-east-1') } before do @@ -17,10 +30,35 @@ end context "some parameters are different" do - let(:stack1) { double(:stack1, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') } - let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 2}, stack_status: 'CREATE_COMPLETE') } - let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } - let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } + let(:stack1) do + double( + :stack1, + template_body: '{}', + template_hash: {}, + template_format: :json, + parameters_with_defaults: { a: 1 }, + stack_status: 'UPDATE_COMPLETE' + ) + end + + let(:stack2) do + double( + :stack2, + template_body: '{}', + template_hash: {}, + template_format: :json, + parameters_with_defaults: { a: 2 }, + stack_status: 'CREATE_COMPLETE' + ) + end + + let(:proposed_stack1) do + double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end + + let(:proposed_stack2) do + double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end it "returns the status of call stacks" do out = <<~OUTPUT @@ -35,10 +73,35 @@ end context "some templates are different" do - let(:stack1) { double(:stack1, template_body: '{"foo": "bar"}', template_hash: {foo: 'bar'}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') } - let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'CREATE_COMPLETE') } - let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } - let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } + let(:stack1) do + double( + :stack1, + template_body: '{"foo": "bar"}', + template_hash: { foo: 'bar' }, + template_format: :json, + parameters_with_defaults: { a: 1 }, + stack_status: 'UPDATE_COMPLETE' + ) + end + + let(:stack2) do + double( + :stack2, + template_body: '{}', + template_hash: {}, + template_format: :json, + parameters_with_defaults: { a: 1 }, + stack_status: 'CREATE_COMPLETE' + ) + end + + let(:proposed_stack1) do + double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end + + let(:proposed_stack2) do + double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end it "returns the status of call stacks" do out = <<~OUTPUT @@ -54,19 +117,51 @@ context 'when identity account is not allowed' do let(:sts) { Aws::STS::Client.new(stub_responses: true) } - let(:stack_definition_1) { double(:stack_definition_1, region: 'us-east-1', stack_name: 'stack1', allowed_accounts: ['not-account-id']) } - let(:stack1) { double(:stack1, template_body: '{"foo": "bar"}', template_hash: {foo: 'bar'}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'UPDATE_COMPLETE') } - let(:stack2) { double(:stack2, template_body: '{}', template_hash: {}, template_format: :json, parameters_with_defaults: {a: 1}, stack_status: 'CREATE_COMPLETE') } - let(:proposed_stack1) { double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } - let(:proposed_stack2) { double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: {a: 1}) } + + let(:stack_definition_1) do + double(:stack_definition_1, region: 'us-east-1', stack_name: 'stack1', allowed_accounts: ['not-account-id']) + end + + let(:stack1) do + double( + :stack1, + template_body: '{"foo": "bar"}', + template_hash: { foo: 'bar' }, + template_format: :json, + parameters_with_defaults: { a: 1 }, + stack_status: 'UPDATE_COMPLETE' + ) + end + + let(:stack2) do + double( + :stack2, + template_body: '{}', + template_hash: {}, + template_format: :json, + parameters_with_defaults: { a: 1 }, + stack_status: 'CREATE_COMPLETE' + ) + end + + let(:proposed_stack1) do + double(:proposed_stack1, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end + + let(:proposed_stack2) do + double(:proposed_stack2, template_body: "{}", template_format: :json, parameters_with_defaults: { a: 1 }) + end before do allow(Aws::STS::Client).to receive(:new).and_return(sts) - sts.stub_responses(:get_caller_identity, { - account: 'account-id', - arn: 'an-arn', - user_id: 'a-user-id' - }) + sts.stub_responses( + :get_caller_identity, + { + account: 'account-id', + arn: 'an-arn', + user_id: 'a-user-id' + } + ) end it 'sets stack status and different fields accordingly' do @@ -91,16 +186,15 @@ it "returns the status of call stacks" do out = <<~OUTPUT - REGION | STACK_NAME | STACK_STATUS | DIFFERENT - ----------|------------|-----------------|---------- - us-east-1 | stack1 | UPDATE_COMPLETE | Yes - us-east-1 | stack2 | CREATE_COMPLETE | No - * No echo parameters can't be diffed + REGION | STACK_NAME | STACK_STATUS | DIFFERENT + ----------|------------|-----------------|---------- + us-east-1 | stack1 | UPDATE_COMPLETE | Yes + us-east-1 | stack2 | CREATE_COMPLETE | No + * No echo parameters can't be diffed OUTPUT expect { status.perform }.to output(out).to_stdout end end end end - end diff --git a/spec/stack_master/commands/validate_spec.rb b/spec/stack_master/commands/validate_spec.rb index de293c32..697af6fb 100644 --- a/spec/stack_master/commands/validate_spec.rb +++ b/spec/stack_master/commands/validate_spec.rb @@ -1,5 +1,4 @@ RSpec.describe StackMaster::Commands::Validate do - subject(:validate) { described_class.new(config, stack_definition, options) } let(:config) { instance_double(StackMaster::Config) } let(:region) { "us-east-1" } @@ -23,5 +22,4 @@ end end end - end diff --git a/spec/stack_master/config_spec.rb b/spec/stack_master/config_spec.rb index aecc9126..6a866847 100644 --- a/spec/stack_master/config_spec.rb +++ b/spec/stack_master/config_spec.rb @@ -94,37 +94,46 @@ end it 'loads stack defaults' do - expect(loaded_config.stack_defaults).to eq({ - 'allowed_accounts' => ["555555555"], - 'tags' => { 'application' => 'my-awesome-blog' }, - 's3' => { 'bucket' => 'my-bucket', 'region' => 'us-east-1' } - }) + expect(loaded_config.stack_defaults) + .to eq( + { + 'allowed_accounts' => ["555555555"], + 'tags' => { 'application' => 'my-awesome-blog' }, + 's3' => { 'bucket' => 'my-bucket', 'region' => 'us-east-1' } + } + ) end it 'loads template compiler mappings' do - expect(loaded_config.template_compilers).to eq({ - rb: :ruby_dsl, - json: :json, - yml: :yaml, - yaml: :yaml, - erb: :yaml_erb, - }) + expect(loaded_config.template_compilers) + .to eq( + { + rb: :ruby_dsl, + json: :json, + yml: :yaml, + yaml: :yaml, + erb: :yaml_erb, + } + ) end it 'loads region defaults' do - expect(loaded_config.region_defaults).to eq({ - 'us-east-1' => { - 'tags' => { 'environment' => 'production' }, - 'role_arn' => 'test_service_role_arn', - 'notification_arns' => ['test_arn'], - 'stack_policy_file' => 'my_policy.json' - }, - 'ap-southeast-2' => { - 'tags' => {'environment' => 'staging', 'test_override' => 1 }, - 'role_arn' => 'test_service_role_arn3', - 'notification_arns' => ['test_arn_3'], - } - }) + expect(loaded_config.region_defaults) + .to eq( + { + 'us-east-1' => { + 'tags' => { 'environment' => 'production' }, + 'role_arn' => 'test_service_role_arn', + 'notification_arns' => ['test_arn'], + 'stack_policy_file' => 'my_policy.json' + }, + 'ap-southeast-2' => { + 'tags' => { 'environment' => 'staging', 'test_override' => 1 }, + 'role_arn' => 'test_service_role_arn3', + 'notification_arns' => ['test_arn_3'], + } + } + ) end it 'loads region_aliases' do @@ -135,44 +144,51 @@ end it 'deep merges stack attributes' do - expect(loaded_config.find_stack('ap-southeast-2', 'myapp-vpc')).to eq(StackMaster::StackDefinition.new( - stack_name: 'myapp-vpc', - region: 'ap-southeast-2', - region_alias: 'staging', - allowed_accounts: ["555555555"], - tags: { - 'application' => 'my-awesome-blog', - 'environment' => 'staging', - 'test_override' => 1 - }, - s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }, - role_arn: 'test_service_role_arn4', - notification_arns: ['test_arn_3', 'test_arn_4'], - template: 'myapp_vpc.rb', - base_dir: base_dir, - additional_parameter_lookup_dirs: ['staging'] - )) - expect(loaded_config.find_stack('ap-southeast-2', 'myapp-web')).to eq(StackMaster::StackDefinition.new( - stack_name: 'myapp-web', - region: 'ap-southeast-2', - region_alias: 'staging', - allowed_accounts: ["1234567890", "9876543210"], - tags: { - 'application' => 'my-awesome-blog', - 'environment' => 'staging', - 'test_override' => 2 - }, - s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }, - role_arn: 'test_service_role_arn3', - notification_arns: ['test_arn_3'], - template: 'myapp_web', - base_dir: base_dir, - additional_parameter_lookup_dirs: ['staging'] - )) + expect(loaded_config.find_stack('ap-southeast-2', 'myapp-vpc')) + .to eq( + StackMaster::StackDefinition.new( + stack_name: 'myapp-vpc', + region: 'ap-southeast-2', + region_alias: 'staging', + allowed_accounts: ["555555555"], + tags: { 'application' => 'my-awesome-blog', 'environment' => 'staging', 'test_override' => 1 }, + s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }, + role_arn: 'test_service_role_arn4', + notification_arns: ['test_arn_3', 'test_arn_4'], + template: 'myapp_vpc.rb', + base_dir: base_dir, + additional_parameter_lookup_dirs: ['staging'] + ) + ) + expect(loaded_config.find_stack('ap-southeast-2', 'myapp-web')) + .to eq( + StackMaster::StackDefinition.new( + stack_name: 'myapp-web', + region: 'ap-southeast-2', + region_alias: 'staging', + allowed_accounts: ["1234567890", "9876543210"], + tags: { 'application' => 'my-awesome-blog', 'environment' => 'staging', 'test_override' => 2 }, + s3: { 'bucket' => 'my-bucket', 'region' => 'us-east-1' }, + role_arn: 'test_service_role_arn3', + notification_arns: ['test_arn_3'], + template: 'myapp_web', + base_dir: base_dir, + additional_parameter_lookup_dirs: ['staging'] + ) + ) end it 'allows region aliases in region defaults' do - config = StackMaster::Config.new({'region_aliases' => { 'production' => 'us-east-1' }, 'region_defaults' => { 'production' => { 'secret_file' => 'production.yml.gpg' }}, 'stacks' => {}}, '/base') - expect(config.region_defaults).to eq('us-east-1' => { 'secret_file' => 'production.yml.gpg' }) + config = StackMaster::Config.new( + { + 'region_aliases' => { 'production' => 'us-east-1' }, + 'region_defaults' => { 'production' => { 'secret_file' => 'production.yml.gpg' } }, + 'stacks' => {} + }, + '/base' + ) + + expect(config.region_defaults) + .to eq('us-east-1' => { 'secret_file' => 'production.yml.gpg' }) end end diff --git a/spec/stack_master/identity_spec.rb b/spec/stack_master/identity_spec.rb index 53354227..c1df0fdd 100644 --- a/spec/stack_master/identity_spec.rb +++ b/spec/stack_master/identity_spec.rb @@ -50,12 +50,15 @@ context 'without list account aliases permissions' do before do - allow(iam).to receive(:list_account_aliases).and_raise( - Aws::IAM::Errors.error_class('AccessDenied').new( - an_instance_of(Seahorse::Client::RequestContext), - 'User: arn:aws:sts::123456789:assumed-role/my-role/123456789012 is not authorized to perform: iam:ListAccountAliases on resource: *' + allow(iam) + .to receive(:list_account_aliases) + .and_raise( + Aws::IAM::Errors.error_class('AccessDenied').new( + an_instance_of(Seahorse::Client::RequestContext), + 'User: arn:aws:sts::123456789:assumed-role/my-role/123456789012 ' \ + 'is not authorized to perform: iam:ListAccountAliases on resource: *' + ) ) - ) end it 'returns false' do @@ -68,10 +71,13 @@ let(:account_aliases) { ['allowed-account'] } before do - iam.stub_responses(:list_account_aliases, { - account_aliases: account_aliases, - is_truncated: false - }) + iam.stub_responses( + :list_account_aliases, + { + account_aliases: account_aliases, + is_truncated: false + } + ) end context "when it's allowed" do @@ -102,12 +108,15 @@ let(:allowed_accounts) { ['an-account-alias'] } before do - allow(iam).to receive(:list_account_aliases).and_raise( - Aws::IAM::Errors.error_class('AccessDenied').new( - an_instance_of(Seahorse::Client::RequestContext), - 'User: arn:aws:sts::123456789:assumed-role/my-role/123456789012 is not authorized to perform: iam:ListAccountAliases on resource: *' + allow(iam) + .to receive(:list_account_aliases) + .and_raise( + Aws::IAM::Errors.error_class('AccessDenied').new( + an_instance_of(Seahorse::Client::RequestContext), + 'User: arn:aws:sts::123456789:assumed-role/my-role/123456789012 ' \ + 'is not authorized to perform: iam:ListAccountAliases on resource: *' + ) ) - ) end it 'raises the correct error' do @@ -119,11 +128,14 @@ describe '#account' do before do - sts.stub_responses(:get_caller_identity, { - account: 'account-id', - arn: 'an-arn', - user_id: 'a-user-id' - }) + sts.stub_responses( + :get_caller_identity, + { + account: 'account-id', + arn: 'an-arn', + user_id: 'a-user-id' + } + ) end it 'returns the current identity account' do @@ -133,10 +145,13 @@ describe '#account_aliases' do before do - iam.stub_responses(:list_account_aliases, { - account_aliases: %w(my-account new-account-name), - is_truncated: false - }) + iam.stub_responses( + :list_account_aliases, + { + account_aliases: %w(my-account new-account-name), + is_truncated: false + } + ) end it 'returns the current identity account aliases' do @@ -145,19 +160,23 @@ context "when identity doesn't have the required iam permissions" do before do - allow(iam).to receive(:list_account_aliases).and_raise( - Aws::IAM::Errors.error_class('AccessDenied').new( - an_instance_of(Seahorse::Client::RequestContext), - 'User: arn:aws:sts::123456789:assumed-role/my-role/987654321000 is not authorized to perform: iam:ListAccountAliases on resource: *' + allow(iam) + .to receive(:list_account_aliases) + .and_raise( + Aws::IAM::Errors.error_class('AccessDenied').new( + an_instance_of(Seahorse::Client::RequestContext), + 'User: arn:aws:sts::123456789:assumed-role/my-role/987654321000 ' \ + 'is not authorized to perform: iam:ListAccountAliases on resource: *' + ) ) - ) end it 'raises an error' do - expect { identity.account_aliases }.to raise_error( - StackMaster::Identity::MissingIamPermissionsError, - 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases' - ) + expect { identity.account_aliases } + .to raise_error( + StackMaster::Identity::MissingIamPermissionsError, + 'Failed to retrieve account aliases. Missing required IAM permission: iam:ListAccountAliases' + ) end end end diff --git a/spec/stack_master/paged_response_accumulator_spec.rb b/spec/stack_master/paged_response_accumulator_spec.rb index 558836ce..7d65aeb9 100644 --- a/spec/stack_master/paged_response_accumulator_spec.rb +++ b/spec/stack_master/paged_response_accumulator_spec.rb @@ -3,10 +3,12 @@ subject(:accumulator) { described_class.new(cf, :describe_stack_events, { stack_name: 'blah' }, :stack_events) } context 'with one page' do - let(:page_one_events) { [ - { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now}, - { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now} - ] } + let(:page_one_events) { + [ + { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now }, + { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now } + ] + } before do cf.stub_responses(:describe_stack_events, { stack_events: page_one_events, next_token: nil }) @@ -19,16 +21,24 @@ end context 'with two pages' do - let(:page_one_events) { [ - { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now}, - { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now} - ] } - let(:page_two_events) { [ - { event_id: '3', stack_id: '1', stack_name: 'blah', timestamp: Time.now} - ] } + let(:page_one_events) { + [ + { event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now }, + { event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now } + ] + } + let(:page_two_events) { + [ + { event_id: '3', stack_id: '1', stack_name: 'blah', timestamp: Time.now } + ] + } before do - cf.stub_responses(:describe_stack_events, { stack_events: page_one_events, next_token: 'blah' }, { stack_events: page_two_events } ) + cf.stub_responses( + :describe_stack_events, + { stack_events: page_one_events, next_token: 'blah' }, + { stack_events: page_two_events } + ) end it 'returns all the stack events combined' do diff --git a/spec/stack_master/parameter_loader_spec.rb b/spec/stack_master/parameter_loader_spec.rb index 4e2db105..aa6bfd9d 100644 --- a/spec/stack_master/parameter_loader_spec.rb +++ b/spec/stack_master/parameter_loader_spec.rb @@ -10,8 +10,8 @@ end context 'no parameter file' do - let(:stack_file_returns) { {exists: false} } - let(:region_file_returns) { {exists: false} } + let(:stack_file_returns) { { exists: false } } + let(:region_file_returns) { { exists: false } } it 'returns empty parameters' do expect(parameters).to eq(template_parameters: {}, compile_time_parameters: {}) @@ -19,45 +19,46 @@ end context 'an empty stack parameter file' do - let(:stack_file_returns) { {exists: true, read: ''} } - let(:region_file_returns) { {exists: false} } + let(:stack_file_returns) { { exists: true, read: '' } } + let(:region_file_returns) { { exists: false } } it 'returns an empty hash' do - expect(parameters).to eq({template_parameters: {}, compile_time_parameters: {}}) + expect(parameters).to eq({ template_parameters: {}, compile_time_parameters: {} }) end end context 'stack parameter file' do - let(:stack_file_returns) { {exists: true, read: 'Param1: value1'} } - let(:region_file_returns) { {exists: false} } + let(:stack_file_returns) { { exists: true, read: 'Param1: value1' } } + let(:region_file_returns) { { exists: false } } it 'returns params from stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {}) + expect(parameters).to eq(template_parameters: { 'Param1' => 'value1' }, compile_time_parameters: {}) end end context 'region parameter file' do - let(:stack_file_returns) { {exists: false } } - let(:region_file_returns) { {exists: true, read: 'Param2: value2'} } + let(:stack_file_returns) { { exists: false } } + let(:region_file_returns) { { exists: true, read: 'Param2: value2' } } it 'returns params from the region base stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param2' => 'value2'}, compile_time_parameters: {}) + expect(parameters).to eq(template_parameters: { 'Param2' => 'value2' }, compile_time_parameters: {}) end end context 'stack and region parameter file' do - let(:stack_file_returns) { {exists: true, read: "Param1: value1\nParam2: valueX" } } - let(:region_file_returns) { {exists: true, read: 'Param2: value2'} } + let(:stack_file_returns) { { exists: true, read: "Param1: value1\nParam2: valueX" } } + let(:region_file_returns) { { exists: true, read: 'Param2: value2' } } it 'returns params from the region base stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param1' => 'value1', 'Param2' => 'value2'}, compile_time_parameters: {}) + expect(parameters).to eq(template_parameters: { 'Param1' => 'value1', 'Param2' => 'value2' }, + compile_time_parameters: {}) end end context 'yml and yaml region parameter files' do - let(:stack_file_returns) { {exists: false} } - let(:region_file_returns) { {exists: true, read: "Param2: value2"} } - let(:region_yaml_file_returns) { {exists: true, read: "Param1: value1\nParam2: valueX"} } + let(:stack_file_returns) { { exists: false } } + let(:region_file_returns) { { exists: true, read: "Param2: value2" } } + let(:region_yaml_file_returns) { { exists: true, read: "Param1: value1\nParam2: valueX" } } let(:region_yaml_file_name) { "/base_dir/parameters/us-east-1/stack_name.yaml" } subject(:parameters) { StackMaster::ParameterLoader.load(parameter_files: [stack_file_name, region_yaml_file_name, region_file_name]) } @@ -67,38 +68,39 @@ end it 'returns params from the region base stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param1' => 'value1', 'Param2' => 'value2'}, compile_time_parameters: {}) + expect(parameters).to eq(template_parameters: { 'Param1' => 'value1', 'Param2' => 'value2' }, + compile_time_parameters: {}) end end context 'compile time parameters' do - context 'stack parameter file' do - let(:stack_file_returns) { {exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: value2" } } - let(:region_file_returns) { {exists: false} } + let(:stack_file_returns) { { exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: value2" } } + let(:region_file_returns) { { exists: false } } it 'returns params from stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {'Param2' => 'value2'}) + expect(parameters).to eq(template_parameters: { 'Param1' => 'value1' }, + compile_time_parameters: { 'Param2' => 'value2' }) end end context 'stack and region parameter file' do - let(:stack_file_returns) { {exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: valueX" } } - let(:region_file_returns) { {exists: true, read: "CompileTimeParameters:\n Param2: value2"} } + let(:stack_file_returns) { { exists: true, read: "Param1: value1\nCompileTimeParameters:\n Param2: valueX" } } + let(:region_file_returns) { { exists: true, read: "CompileTimeParameters:\n Param2: value2" } } it 'returns params from the region base stack_name.yml' do - expect(parameters).to eq(template_parameters: {'Param1' => 'value1'}, compile_time_parameters: {'Param2' => 'value2'}) + expect(parameters).to eq(template_parameters: { 'Param1' => 'value1' }, + compile_time_parameters: { 'Param2' => 'value2' }) end end - end context 'underscored parameter names' do - let(:stack_file_returns) { {exists: true, read: 'vpc_id: vpc-xxxxxx' } } - let(:region_file_returns) { {exists: false} } + let(:stack_file_returns) { { exists: true, read: 'vpc_id: vpc-xxxxxx' } } + let(:region_file_returns) { { exists: false } } it 'camelcases them' do - expect(parameters).to eq(template_parameters: {'VpcId' => 'vpc-xxxxxx'}, compile_time_parameters: {}) + expect(parameters).to eq(template_parameters: { 'VpcId' => 'vpc-xxxxxx' }, compile_time_parameters: {}) end end @@ -106,5 +108,4 @@ def file_mock(file_name, exists: false, read: nil) allow(File).to receive(:exist?).with(file_name).and_return(exists) allow(File).to receive(:read).with(file_name).and_return(read) if read end - end diff --git a/spec/stack_master/parameter_resolver_spec.rb b/spec/stack_master/parameter_resolver_spec.rb index 15dac33e..363b6f13 100644 --- a/spec/stack_master/parameter_resolver_spec.rb +++ b/spec/stack_master/parameter_resolver_spec.rb @@ -99,7 +99,7 @@ def resolve(params) end context 'when assuming a role' do - let(:role_assumer) { instance_double(StackMaster::RoleAssumer, assume_role: nil ) } + let(:role_assumer) { instance_double(StackMaster::RoleAssumer, assume_role: nil) } let(:account) { '1234567890' } let(:role) { 'my-role' } @@ -222,9 +222,20 @@ def resolve(params) end it "tries to load the plural and singular forms" do - expect(parameter_resolver).to receive(:require_parameter_resolver).with("other_dummy_resolvers").once.and_call_original.ordered - expect(parameter_resolver).to receive(:require_parameter_resolver).with("other_dummy_resolver").once.ordered - expect(parameter_resolver).to receive(:call_resolver).and_return nil + expect(parameter_resolver) + .to receive(:require_parameter_resolver) + .with("other_dummy_resolvers") + .once + .and_call_original + .ordered + expect(parameter_resolver) + .to receive(:require_parameter_resolver) + .with("other_dummy_resolver") + .once + .ordered + expect(parameter_resolver) + .to receive(:call_resolver) + .and_return nil parameter_resolver.resolve end diff --git a/spec/stack_master/parameter_resolvers/ami_finder_spec.rb b/spec/stack_master/parameter_resolvers/ami_finder_spec.rb index e3041a32..b03bdc5b 100644 --- a/spec/stack_master/parameter_resolvers/ami_finder_spec.rb +++ b/spec/stack_master/parameter_resolvers/ami_finder_spec.rb @@ -10,7 +10,7 @@ context 'when a single key-value pair is specified' do it 'returns an array with a single hash' do expect(resolver.build_filters_from_string('my-attr=my-value', nil)).to eq [ - { name: 'my-attr', values: ['my-value']} + { name: 'my-attr', values: ['my-value'] } ] end end @@ -18,8 +18,8 @@ context 'when multiple key-value pairs are specified' do it 'returns an array with multiple hashes' do expect(resolver.build_filters_from_string('my-attr=my-value,foo=bar', nil)).to eq [ - { name: 'my-attr', values: ['my-value']}, - { name: 'foo', values: ['bar']} + { name: 'my-attr', values: ['my-value'] }, + { name: 'foo', values: ['bar'] } ] end end @@ -27,7 +27,7 @@ context 'when a prefix is supplied' do it 'adds the prefix to the filter' do expect(resolver.build_filters_from_string('my-tag=my-value', 'tag')).to eq [ - { name: 'tag:my-tag', values: ['my-value']} + { name: 'tag:my-tag', values: ['my-value'] } ] end end @@ -35,12 +35,12 @@ describe '#build_filters_from_hash' do it 'outputs a hash of values in the format expected by the AWS API' do - expect(resolver.build_filters_from_hash({'foo' => 'bacon'})).to eq([{name: 'foo', values: ['bacon']}]) + expect(resolver.build_filters_from_hash({ 'foo' => 'bacon' })).to eq([{ name: 'foo', values: ['bacon'] }]) end end describe '#find_latest_ami' do - let(:filter) { [{ name: "String", values: ["String"]}] } + let(:filter) { [{ name: "String", values: ["String"] }] } context 'when matches are found' do before do diff --git a/spec/stack_master/parameter_resolvers/ejson_spec.rb b/spec/stack_master/parameter_resolvers/ejson_spec.rb index b1acf2e1..855400b7 100644 --- a/spec/stack_master/parameter_resolvers/ejson_spec.rb +++ b/spec/stack_master/parameter_resolvers/ejson_spec.rb @@ -3,7 +3,15 @@ let(:config) { double(base_dir: base_dir) } let(:ejson_file) { 'staging.ejson' } let(:ejson_file_region) { 'ap-southeast-2' } - let(:stack_definition) { double(ejson_file: ejson_file, ejson_file_region: ejson_file_region, stack_name: 'mystack', region: 'us-east-1', ejson_file_kms: true) } + let(:stack_definition) do + double( + ejson_file: ejson_file, + ejson_file_region: ejson_file_region, + stack_name: 'mystack', + region: 'us-east-1', + ejson_file_kms: true + ) + end subject(:ejson) { described_class.new(config, stack_definition) } let(:secrets) { { secret_a: 'value_a', secret_b: 'value_b' } } @@ -26,7 +34,9 @@ it 'decrypts with the correct file path' do ejson.resolve('secret_a') - expect(EJSONWrapper).to have_received(:decrypt).with('/base_dir/secrets/staging.ejson', use_kms: true, region: StackMaster.cloud_formation_driver.region) + expect(EJSONWrapper) + .to have_received(:decrypt) + .with('/base_dir/secrets/staging.ejson', use_kms: true, region: StackMaster.cloud_formation_driver.region) end end @@ -35,7 +45,9 @@ it 'decrypts with the correct file path' do ejson.resolve('secret_a') - expect(EJSONWrapper).to have_received(:decrypt).with('/base_dir/secrets/staging.ejson', use_kms: true, region: 'ap-southeast-2') + expect(EJSONWrapper) + .to have_received(:decrypt) + .with('/base_dir/secrets/staging.ejson', use_kms: true, region: 'ap-southeast-2') end end diff --git a/spec/stack_master/parameter_resolvers/env_spec.rb b/spec/stack_master/parameter_resolvers/env_spec.rb index b6f1be46..fa1a3a12 100644 --- a/spec/stack_master/parameter_resolvers/env_spec.rb +++ b/spec/stack_master/parameter_resolvers/env_spec.rb @@ -1,7 +1,5 @@ RSpec.describe StackMaster::ParameterResolvers::Env do - describe '#resolve' do - subject(:resolver) { described_class.new(nil, double(region: 'us-east-1')) } let(:environment_variable_name) { 'TEST' } let(:error) { "The environment variable #{environment_variable_name} is not set" } @@ -20,7 +18,7 @@ context 'the environment variable is undefined' do it 'should raise and error' do expect { resolver.resolve(environment_variable_name) } - .to raise_error(ArgumentError, error) + .to raise_error(ArgumentError, error) end end @@ -30,6 +28,5 @@ expect(resolver.resolve(environment_variable_name)).to eq '' end end - end end diff --git a/spec/stack_master/parameter_resolvers/latest_ami_spec.rb b/spec/stack_master/parameter_resolvers/latest_ami_spec.rb index 67fc1f84..3603ea6c 100644 --- a/spec/stack_master/parameter_resolvers/latest_ami_spec.rb +++ b/spec/stack_master/parameter_resolvers/latest_ami_spec.rb @@ -22,7 +22,7 @@ end it 'returns the latest one' do - expect(resolver.resolve('filters' => {'name' => 'foo'})).to eq '2' + expect(resolver.resolve('filters' => { 'name' => 'foo' })).to eq '2' end end @@ -32,7 +32,7 @@ end it 'returns nil' do - expect(resolver.resolve('filters' => {'name' => 'foo'})).to be_nil + expect(resolver.resolve('filters' => { 'name' => 'foo' })).to be_nil end end @@ -44,8 +44,8 @@ end it 'calls find_latest_ami with the owner and filters' do - expect(ami_finder).to receive(:find_latest_ami).with([{name: 'foo', values: ['bacon']}], ['123456']) - resolver.resolve({'owners' => 123456, 'filters' => {'foo' => 'bacon'} }) + expect(ami_finder).to receive(:find_latest_ami).with([{ name: 'foo', values: ['bacon'] }], ['123456']) + resolver.resolve({ 'owners' => 123456, 'filters' => { 'foo' => 'bacon' } }) end end end diff --git a/spec/stack_master/parameter_resolvers/latest_container_spec.rb b/spec/stack_master/parameter_resolvers/latest_container_spec.rb index 5333da53..c2a8dd37 100644 --- a/spec/stack_master/parameter_resolvers/latest_container_spec.rb +++ b/spec/stack_master/parameter_resolvers/latest_container_spec.rb @@ -15,15 +15,26 @@ { next_token: nil, image_details: [ - { registry_id: '012345678910', image_digest: 'sha256:decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, - { registry_id: '012345678910', image_digest: 'sha256:deadbeef', image_pushed_at: Time.utc(2015,1,3,0,0), image_tags: ['v2'] } + { + registry_id: '012345678910', + image_digest: 'sha256:decafc0ffee', + image_pushed_at: Time.utc(2015, 1, 2, 0, 0), + image_tags: ['v1'] + }, + { + registry_id: '012345678910', + image_digest: 'sha256:deadbeef', + image_pushed_at: Time.utc(2015, 1, 3, 0, 0), + image_tags: ['v2'] + } ] } ) end it 'returns the latest one' do - expect(resolver.resolve({'repository_name' => 'foo'})).to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:deadbeef' + expect(resolver.resolve({ 'repository_name' => 'foo' })) + .to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:deadbeef' end end @@ -33,7 +44,7 @@ end it 'returns nil' do - expect(resolver.resolve({'repository_name' => 'foo'})).to be_nil + expect(resolver.resolve({ 'repository_name' => 'foo' })).to be_nil end end @@ -44,22 +55,34 @@ { next_token: nil, image_details: [ - { registry_id: '012345678910', image_digest: 'sha256:decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1', 'production'] }, - { registry_id: '012345678910', image_digest: 'sha256:deadbeef', image_pushed_at: Time.utc(2015,1,3,0,0), image_tags: ['v2'] } + { + registry_id: '012345678910', + image_digest: 'sha256:decafc0ffee', + image_pushed_at: Time.utc(2015, 1, 2, 0, 0), + image_tags: ['v1', 'production'] + }, + { + registry_id: '012345678910', + image_digest: 'sha256:deadbeef', + image_pushed_at: Time.utc(2015, 1, 3, 0, 0), + image_tags: ['v2'] + } ] } ) end - + context 'when image exists' do it 'returns the image with the production tag' do - expect(resolver.resolve({'repository_name' => 'foo', 'tag' => 'production'})).to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:decafc0ffee' + expect(resolver.resolve({ 'repository_name' => 'foo', 'tag' => 'production' })) + .to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:decafc0ffee' end end context 'when no image exists for this tag' do it 'returns nil' do - expect(resolver.resolve({'repository_name' => 'foo', 'tag' => 'nosuchtag'})).to be_nil + expect(resolver.resolve({ 'repository_name' => 'foo', 'tag' => 'nosuchtag' })) + .to be_nil end end end @@ -71,34 +94,77 @@ { next_token: nil, image_details: [ - { registry_id: '012345678910', image_digest: 'sha256:decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, + { + registry_id: '012345678910', + image_digest: 'sha256:decafc0ffee', + image_pushed_at: Time.utc(2015, 1, 2, 0, 0), + image_tags: ['v1'] + }, ] } ) end it 'passes registry_id to describe_images' do - expect(ecr).to receive(:describe_images).with({repository_name: "foo", registry_id: "012345678910", next_token: nil, filter: {:tag_status=>"TAGGED"}}) - resolver.resolve({'repository_name' => 'foo', 'registry_id' => '012345678910'}) + expect(ecr) + .to receive(:describe_images) + .with( + { + repository_name: "foo", + registry_id: "012345678910", + next_token: nil, + filter: { :tag_status => "TAGGED" } + } + ) + resolver.resolve({ 'repository_name' => 'foo', 'registry_id' => '012345678910' }) end end context 'when there are multiple pages' do before do - ecr.stub_responses(:describe_images, [ - { next_token: '1', image_details: [ - { registry_id: '012345678910', image_digest: 'sha256:decafc0ffee', image_pushed_at: Time.utc(2015,1,2,0,0), image_tags: ['v1'] }, - { registry_id: '012345678910', image_digest: 'sha256:deadbeef', image_pushed_at: Time.utc(2015,1,3,0,0), image_tags: ['latest', 'v2'] } - ]}, - { next_token: nil, image_details: [ - { registry_id: '012345678910', image_digest: 'sha256:badf00d', image_pushed_at: Time.utc(2015,1,4,0,0), image_tags: ['v3'] }, - { registry_id: '012345678910', image_digest: 'sha256:d15ea5e', image_pushed_at: Time.utc(2015,1,5,0,0), image_tags: ['v4'] } - ]} - ]) + ecr.stub_responses( + :describe_images, [ + { + next_token: '1', + image_details: [ + { + registry_id: '012345678910', + image_digest: 'sha256:decafc0ffee', + image_pushed_at: Time.utc(2015, 1, 2, 0, 0), + image_tags: ['v1'] + }, + { + registry_id: '012345678910', + image_digest: 'sha256:deadbeef', + image_pushed_at: Time.utc(2015, 1, 3, 0, 0), + image_tags: ['latest', 'v2'] + } + ] + }, + { + next_token: nil, + image_details: [ + { + registry_id: '012345678910', + image_digest: 'sha256:badf00d', + image_pushed_at: Time.utc(2015, 1, 4, 0, 0), + image_tags: ['v3'] + }, + { + registry_id: '012345678910', + image_digest: 'sha256:d15ea5e', + image_pushed_at: Time.utc(2015, 1, 5, 0, 0), + image_tags: ['v4'] + } + ] + } + ] + ) end it 'takes all pages into account' do - expect(resolver.resolve({'repository_name' => 'foo'})).to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:d15ea5e' + expect(resolver.resolve({ 'repository_name' => 'foo' })) + .to eq '012345678910.dkr.ecr.us-east-1.amazonaws.com/foo@sha256:d15ea5e' end end end diff --git a/spec/stack_master/parameter_resolvers/one_password_spec.rb b/spec/stack_master/parameter_resolvers/one_password_spec.rb index 72940b32..40703a9e 100644 --- a/spec/stack_master/parameter_resolvers/one_password_spec.rb +++ b/spec/stack_master/parameter_resolvers/one_password_spec.rb @@ -1,136 +1,185 @@ RSpec.describe StackMaster::ParameterResolvers::OnePassword do - describe '#resolve' do let(:config) { double(base_dir: '/base') } let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') } subject(:resolver) { described_class.new(config, stack_definition) } - let(:op_env_unset) { ENV['OP_SESSION_something'].clear } - let(:secureNote) {{ - "uuid" => "auuid", - "vaultUuid" => "avaultuuid", - "templateUuid" => "003", - "createdAt" => "2018-01-17 07:28:11 +0000 UTC", - "updatedAt" => "2018-01-17 07:28:11 +0000 UTC", - "changerUuid" => "anotheruuid", - "overview" => { - "ainfo" => "begin message", - "ps" => 0, - "title" => "note title" - }, - "details" => { - "notesPlain" => "decrypted note", - "sections" => [ - { - "name" => "linked items", - "title" => "Related Items" - } - ] + let(:op_env_unset) { ENV['OP_SESSION_something'].clear } + let(:secureNote) { + { + "uuid" => "auuid", + "vaultUuid" => "avaultuuid", + "templateUuid" => "003", + "createdAt" => "2018-01-17 07:28:11 +0000 UTC", + "updatedAt" => "2018-01-17 07:28:11 +0000 UTC", + "changerUuid" => "anotheruuid", + "overview" => { + "ainfo" => "begin message", + "ps" => 0, + "title" => "note title" + }, + "details" => { + "notesPlain" => "decrypted note", + "sections" => [ + { + "name" => "linked items", + "title" => "Related Items" + } + ] + } } - }} - let(:login_password) {{ - "uuid" => "auuid", - "vaultUuid" => "avaultuuid", - "templateUuid" => "001", - "createdAt" => "2018-03-24 01:55:07 +0000 UTC", - "updatedAt" => "2018-03-24 01:55:07 +0000 UTC", - "changerUuid" => "anotheruuid", - "overview" => { - "ainfo" => "pi", - "ps" => 84, - "title" => "password title" - }, - "details" => { - "fields" => [ - { - "designation" => "username", - "name" => "username", - "type" => "T", - "value" => "theusername" - }, - { - "designation" => "password", - "name" => "password", - "type" => "P", - "value" => "thepassword" - } - ], - "sections" => [ - { - "name" => "linked items", - "title" => "Related Items" - } - ] + } + let(:login_password) { + { + "uuid" => "auuid", + "vaultUuid" => "avaultuuid", + "templateUuid" => "001", + "createdAt" => "2018-03-24 01:55:07 +0000 UTC", + "updatedAt" => "2018-03-24 01:55:07 +0000 UTC", + "changerUuid" => "anotheruuid", + "overview" => { + "ainfo" => "pi", + "ps" => 84, + "title" => "password title" + }, + "details" => { + "fields" => [ + { + "designation" => "username", + "name" => "username", + "type" => "T", + "value" => "theusername" + }, + { + "designation" => "password", + "name" => "password", + "type" => "P", + "value" => "thepassword" + } + ], + "sections" => [ + { + "name" => "linked items", + "title" => "Related Items" + } + ] + } } - }} - let(:password) {{ - "uuid" => "auuid", - "vaultUuid" => "avaultuuid", - "templateUuid" => "005", - "createdAt" => "2018-04-24 11:07:34 +0000 UTC", - "updatedAt" => "2018-04-24 11:07:34 +0000 UTC", - "changerUuid" => "antheruuid", - "overview" => { - "ainfo" => "24 Apr 2018, 9:07:34 pm", - "ps" => 100, - "title" => "password title" - }, - "details" => { - "password" => "thepassword", - "sections" => [ - { - "name" => "linked items", - "title" => "Related Items" - } - ] + } + let(:password) { + { + "uuid" => "auuid", + "vaultUuid" => "avaultuuid", + "templateUuid" => "005", + "createdAt" => "2018-04-24 11:07:34 +0000 UTC", + "updatedAt" => "2018-04-24 11:07:34 +0000 UTC", + "changerUuid" => "antheruuid", + "overview" => { + "ainfo" => "24 Apr 2018, 9:07:34 pm", + "ps" => 100, + "title" => "password title" + }, + "details" => { + "password" => "thepassword", + "sections" => [ + { + "name" => "linked items", + "title" => "Related Items" + } + ] + } } - }} - let(:the_password) {{ + } + let(:the_password) { + { 'title' => 'password title', 'type' => 'password', 'vault' => 'Shared' - }} - let(:the_secureNote) {{ + } + } + let(:the_secureNote) { + { 'title' => 'note title', 'type' => 'secureNote', 'vault' => 'Shared' - }} + } + } context 'when we have set OP_SESSION_ environment' do before do ENV['OP_SESSION_something'] = 'session' end + context 'when retrieving a login password' do it 'returns the login password' do - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'password title' 2>&1").and_return(login_password.to_json) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'password title' 2>&1") + .and_return(login_password.to_json) + expect(resolver.resolve(the_password)).to eq 'thepassword' end end + context 'when retrieving a password' do it 'returns the password' do - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'password title' 2>&1").and_return(password.to_json) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'password title' 2>&1") + .and_return(password.to_json) + expect(resolver.resolve(the_password)).to eq 'thepassword' end end + context 'when retrieving a secureNote' do it 'returns the secureNote' do - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'note title' 2>&1").and_return(secureNote.to_json) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'note title' 2>&1") + .and_return(secureNote.to_json) + expect(resolver.resolve(the_secureNote)).to eq 'decrypted note' end end end + context 'when we have not set OP_SESSION_ environment' do context 'when retrieving a password' do it 'should raise error when ENV not set' do - allow(ENV).to receive_message_chain(:keys, :grep).with(/OP_SESSION_\w+$/).and_return([]) - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'password title' 2>&1").and_return(password.to_json) - expect { resolver.resolve(the_password) }.to raise_error(StackMaster::ParameterResolvers::OnePassword::OnePasswordNotAbleToAuthenticate, "1password requires the `OP_SESSION_` to be set, (remember to sign in?)") + allow(ENV) + .to receive_message_chain(:keys, :grep) + .with(/OP_SESSION_\w+$/) + .and_return([]) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'password title' 2>&1") + .and_return(password.to_json) + + expect { resolver.resolve(the_password) } + .to raise_error( + StackMaster::ParameterResolvers::OnePassword::OnePasswordNotAbleToAuthenticate, + "1password requires the `OP_SESSION_` to be set, (remember to sign in?)" + ) end end end + context 'when we op cli is not installed' do before do ENV['OP_SESSION_something'] = 'session' @@ -138,27 +187,58 @@ it 'we return an error' do allow_any_instance_of(described_class).to receive(:`).with("op --version").and_raise(Errno::ENOENT) - expect { resolver.resolve(the_password) }.to raise_error(StackMaster::ParameterResolvers::OnePassword::OnePasswordBinaryNotFound, "The op cli needs to be installed and in the PATH, No such file or directory") + + expect { resolver.resolve(the_password) } + .to raise_error( + StackMaster::ParameterResolvers::OnePassword::OnePasswordBinaryNotFound, + "The op cli needs to be installed and in the PATH, No such file or directory" + ) end end + context 'when items are not found' do before do ENV['OP_SESSION_something'] = 'session' end + it 'we return an error' do - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'password title' 2>&1").and_return('[LOG] 2018/03/26 09:56:02 (ERROR) Vault Shared not found.') - expect { resolver.resolve(the_password) }.to raise_error(StackMaster::ParameterResolvers::OnePassword::OnePasswordNotFound, 'Failed to return item from 1password, (ERROR) Vault Shared not found.') + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'password title' 2>&1") + .and_return('[LOG] 2018/03/26 09:56:02 (ERROR) Vault Shared not found.') + + expect { resolver.resolve(the_password) } + .to raise_error( + StackMaster::ParameterResolvers::OnePassword::OnePasswordNotFound, + 'Failed to return item from 1password, (ERROR) Vault Shared not found.' + ) end end + context 'when returned value is invalid' do before do ENV['OP_SESSION_something'] = 'session' end + it 'we return an error' do - allow_any_instance_of(described_class).to receive(:`).with("op --version").and_return(true) - allow_any_instance_of(described_class).to receive(:`).with("op get item --vault='Shared' 'password title' 2>&1").and_return('{key: value }') - expect { resolver.resolve(the_password) }.to raise_error(StackMaster::ParameterResolvers::OnePassword::OnePasswordInvalidResponse, /Failed to parse JSON returned, {key: value }:/) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op --version") + .and_return(true) + allow_any_instance_of(described_class) + .to receive(:`) + .with("op get item --vault='Shared' 'password title' 2>&1") + .and_return('{key: value }') + + expect { resolver.resolve(the_password) } + .to raise_error( + StackMaster::ParameterResolvers::OnePassword::OnePasswordInvalidResponse, + /Failed to parse JSON returned, {key: value }:/ + ) end end end diff --git a/spec/stack_master/parameter_resolvers/parameter_store_spec.rb b/spec/stack_master/parameter_resolvers/parameter_store_spec.rb index 0088dd89..98a0b28c 100644 --- a/spec/stack_master/parameter_resolvers/parameter_store_spec.rb +++ b/spec/stack_master/parameter_resolvers/parameter_store_spec.rb @@ -1,7 +1,5 @@ RSpec.describe StackMaster::ParameterResolvers::ParameterStore do - describe '#resolve' do - let(:config) { double(base_dir: '/base') } let(:stack_definition) { double(stack_name: 'mystack', region: 'us-east-1') } subject(:resolver) { described_class.new(config, stack_definition) } @@ -10,7 +8,6 @@ let(:unknown_parameter_name) { 'NOTEST' } let(:unencryptable_parameter_name) { 'SECRETTEST' } - context 'the parameter is defined' do before do Aws.config[:ssm] = { @@ -26,7 +23,7 @@ } } end - + it 'should return the parameter value' do expect(resolver.resolve(parameter_name)).to eq parameter_value end @@ -36,14 +33,20 @@ before do Aws.config[:ssm] = { stub_responses: { - get_parameter: - Aws::SSM::Errors::ParameterNotFound.new(unknown_parameter_name, "Parameter #{unknown_parameter_name} not found") + get_parameter: + Aws::SSM::Errors::ParameterNotFound.new( + unknown_parameter_name, + "Parameter #{unknown_parameter_name} not found" + ) } } end it 'should raise and error' do expect { resolver.resolve(unknown_parameter_name) } - .to raise_error(StackMaster::ParameterResolvers::ParameterStore::ParameterNotFound, "Unable to find #{unknown_parameter_name} in Parameter Store") + .to raise_error( + StackMaster::ParameterResolvers::ParameterStore::ParameterNotFound, + "Unable to find #{unknown_parameter_name} in Parameter Store" + ) end end end diff --git a/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb b/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb index 4f168783..87aaef28 100644 --- a/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb +++ b/spec/stack_master/parameter_resolvers/sns_topic_name_spec.rb @@ -10,7 +10,7 @@ def resolve(value) subject(:resolved_value) { resolve(value) } context 'when given a hash' do - let(:value) { { not_expected: 1} } + let(:value) { { not_expected: 1 } } it 'raises an error' do expect { diff --git a/spec/stack_master/parameter_resolvers/sso_group_id_spec.rb b/spec/stack_master/parameter_resolvers/sso_group_id_spec.rb index abc7d518..85eef6cd 100644 --- a/spec/stack_master/parameter_resolvers/sso_group_id_spec.rb +++ b/spec/stack_master/parameter_resolvers/sso_group_id_spec.rb @@ -47,4 +47,3 @@ end end end - diff --git a/spec/stack_master/parameter_resolvers/stack_output_spec.rb b/spec/stack_master/parameter_resolvers/stack_output_spec.rb index dbbee720..6f979ea5 100644 --- a/spec/stack_master/parameter_resolvers/stack_output_spec.rb +++ b/spec/stack_master/parameter_resolvers/stack_output_spec.rb @@ -22,7 +22,7 @@ def resolve(value) end context 'when given a hash' do - let(:value) { { not_expected: 1} } + let(:value) { { not_expected: 1 } } it 'raises an error' do expect { @@ -33,7 +33,9 @@ def resolve(value) context 'when given a valid string value' do let(:value) { 'my-stack/MyOutput' } - let(:stacks) { [{ stack_name: 'blah', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs}] } + let(:stacks) { + [{ stack_name: 'blah', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs }] + } let(:outputs) { [] } before do @@ -43,7 +45,7 @@ def resolve(value) end context 'the stack and output exist' do - let(:outputs) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue'}] } + let(:outputs) { [{ output_key: 'MyOutput', output_value: 'myresolvedvalue' }] } before do allow(config).to receive(:unalias_region).with('ap-southeast-2').and_return('ap-southeast-2') @@ -69,7 +71,7 @@ def resolve(value) context 'when the output key has a non-camel name' do let(:value) { 'my-stack/my_Output' } - let(:outputs) { [{output_key: 'my_Output', output_value: 'myresolvedvalue'}] } + let(:outputs) { [{ output_key: 'my_Output', output_value: 'myresolvedvalue' }] } it 'resolves the value' do expect(resolved_value).to eq 'myresolvedvalue' @@ -77,8 +79,17 @@ def resolve(value) end context "when different credentials are used" do - let(:outputs_in_account_2) { [ {output_key: 'MyOutput', output_value: 'resolvedvalueinaccount2'} ] } - let(:stacks_in_account_2) { [{ stack_name: 'other-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs_in_account_2}] } + let(:outputs_in_account_2) { [{ output_key: 'MyOutput', output_value: 'resolvedvalueinaccount2' }] } + let(:stacks_in_account_2) { + [ + { + stack_name: 'other-stack', + creation_time: Time.now, + stack_status: 'CREATE_COMPLETE', + outputs: outputs_in_account_2 + } + ] + } before do cf.stub_responses( @@ -137,7 +148,9 @@ def resolve(value) context 'when given a valid string value including region' do let(:value) { 'us-east-1:my-stack/MyOutput' } - let(:stacks) { [{ stack_name: 'my-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs}] } + let(:stacks) { + [{ stack_name: 'my-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs }] + } let(:outputs) { [] } before do @@ -146,7 +159,7 @@ def resolve(value) end context 'the stack and output exist' do - let(:outputs) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue'}] } + let(:outputs) { [{ output_key: 'MyOutput', output_value: 'myresolvedvalue' }] } it 'resolves the value' do expect(resolved_value).to eq 'myresolvedvalue' @@ -155,8 +168,17 @@ def resolve(value) context 'the stack and output exist in a different region with the same name' do let(:value_in_region_alias) { 'global:my-stack/MyOutput' } let(:value_in_region_2) { 'ap-southeast-2:my-stack/MyOutput' } - let(:outputs_in_region_2) { [{output_key: 'MyOutput', output_value: 'myresolvedvalue2'}] } - let(:stacks_in_region_2) { [{ stack_name: 'my-stack', creation_time: Time.now, stack_status: 'CREATE_COMPLETE', outputs: outputs_in_region_2}] } + let(:outputs_in_region_2) { [{ output_key: 'MyOutput', output_value: 'myresolvedvalue2' }] } + let(:stacks_in_region_2) { + [ + { + stack_name: 'my-stack', + creation_time: Time.now, + stack_status: 'CREATE_COMPLETE', + outputs: outputs_in_region_2 + } + ] + } before do cf.stub_responses( diff --git a/spec/stack_master/parameter_validator_spec.rb b/spec/stack_master/parameter_validator_spec.rb index 79d5cdd7..19fbedad 100644 --- a/spec/stack_master/parameter_validator_spec.rb +++ b/spec/stack_master/parameter_validator_spec.rb @@ -9,13 +9,13 @@ subject { parameter_validator.missing_parameters? } context 'when a parameter has a nil value' do - let(:parameters) { {'my_param' => nil} } + let(:parameters) { { 'my_param' => nil } } it { should eq true } end context 'when no parameers have a nil value' do - let(:parameters) { {'my_param' => '1'} } + let(:parameters) { { 'my_param' => '1' } } it { should eq false } end @@ -25,7 +25,7 @@ subject(:error_message) { parameter_validator.error_message } context 'when a parameter has a nil value' do - let(:parameters) { {'Param1' => true, 'Param2' => nil, 'Param3' => 'string', 'Param4' => nil} } + let(:parameters) { { 'Param1' => true, 'Param2' => nil, 'Param3' => 'string', 'Param4' => nil } } it 'returns a descriptive message' do expect(error_message).to eq(<<~MESSAGE) @@ -40,7 +40,7 @@ end context 'when the stack definition is using explicit parameter files' do - let(:parameters) { {'Param1' => true, 'Param2' => nil, 'Param3' => 'string', 'Param4' => nil} } + let(:parameters) { { 'Param1' => true, 'Param2' => nil, 'Param3' => 'string', 'Param4' => nil } } let(:parameter_files) { ["params.yml"] } it 'returns a descriptive message' do @@ -50,12 +50,12 @@ - Param4 Parameters are configured to be read from the following files: - /base_dir/parameters/params.yml - MESSAGE + MESSAGE end end context 'when no parameers have a nil value' do - let(:parameters) { {'Param' => '1'} } + let(:parameters) { { 'Param' => '1' } } it { should eq nil } end diff --git a/spec/stack_master/resolver_array_spec.rb b/spec/stack_master/resolver_array_spec.rb index 2da14518..3741a464 100644 --- a/spec/stack_master/resolver_array_spec.rb +++ b/spec/stack_master/resolver_array_spec.rb @@ -16,7 +16,7 @@ describe '.array_resolver' do context 'when using a default name' do - before do + before do class TestResolver < StackMaster::ParameterResolvers::Resolver array_resolver end @@ -28,12 +28,12 @@ class TestResolver < StackMaster::ParameterResolvers::Resolver end context 'when using a specific name' do - before do + before do class TestResolver < StackMaster::ParameterResolvers::Resolver array_resolver class_name: 'SpecificResolver' end end - + let(:array_resolver_class) { StackMaster::ParameterResolvers::SpecificResolver } it_behaves_like 'a resolver' diff --git a/spec/stack_master/role_assumer_spec.rb b/spec/stack_master/role_assumer_spec.rb index eea7769e..01d1f1fa 100644 --- a/spec/stack_master/role_assumer_spec.rb +++ b/spec/stack_master/role_assumer_spec.rb @@ -16,11 +16,16 @@ end it 'calls the assume role API once' do - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: role_arn, - role_session_name: instance_of(String) - }).once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: role_arn, + role_session_name: instance_of(String) + } + ) + .once assume_role end @@ -34,11 +39,16 @@ end it 'assumes the role before calling block' do - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: role_arn, - role_session_name: instance_of(String) - }).ordered + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: role_arn, + role_session_name: instance_of(String) + } + ) + .ordered expect(my_block).to receive(:call).ordered assume_role @@ -46,11 +56,15 @@ it "uses the cloudformation driver's region" do StackMaster.cloud_formation_driver.set_region('my-region') - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: 'my-region', - role_arn: instance_of(String), - role_session_name: instance_of(String) - }) + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: 'my-region', + role_arn: instance_of(String), + role_session_name: instance_of(String) + } + ) assume_role end @@ -67,7 +81,8 @@ let(:account) { nil } it 'when raises an error' do - expect { assume_role }.to raise_error(ArgumentError, "Both 'account' and 'role' are required to assume a role") + expect { assume_role } + .to raise_error(ArgumentError, "Both 'account' and 'role' are required to assume a role") end end @@ -75,7 +90,8 @@ let(:role) { nil } it 'raises an error' do - expect { assume_role }.to raise_error(ArgumentError, "Both 'account' and 'role' are required to assume a role") + expect { assume_role } + .to raise_error(ArgumentError, "Both 'account' and 'role' are required to assume a role") end end @@ -83,7 +99,9 @@ let(:new_aws_config) { {} } before do - allow(Aws.config).to receive(:deep_dup).and_return(new_aws_config) + allow(Aws.config) + .to receive(:deep_dup) + .and_return(new_aws_config) end it 'updates the global Aws config with the assumed role credentials' do @@ -130,11 +148,16 @@ describe 'when called multiple times' do context 'with the same account and role' do it 'assumes the role once' do - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: role_arn, - role_session_name: instance_of(String) - }).once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: role_arn, + role_session_name: instance_of(String) + } + ) + .once role_assumer.assume_role(account, role, &my_block) role_assumer.assume_role(account, role, &my_block) @@ -143,16 +166,26 @@ context 'with a different account' do it 'assumes each role once' do - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: role_arn, - role_session_name: instance_of(String) - }).once - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: "arn:aws:iam::another-account:role/#{role}", - role_session_name: instance_of(String) - }).once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: role_arn, + role_session_name: instance_of(String) + } + ) + .once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: "arn:aws:iam::another-account:role/#{role}", + role_session_name: instance_of(String) + } + ) + .once role_assumer.assume_role(account, role, &my_block) role_assumer.assume_role('another-account', role, &my_block) @@ -161,16 +194,26 @@ context 'with a different role' do it 'assumes each role once' do - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: role_arn, - role_session_name: instance_of(String) - }).once - expect(Aws::AssumeRoleCredentials).to receive(:new).with({ - region: instance_of(String), - role_arn: "arn:aws:iam::#{account}:role/another-role", - role_session_name: instance_of(String) - }).once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: role_arn, + role_session_name: instance_of(String) + } + ) + .once + expect(Aws::AssumeRoleCredentials) + .to receive(:new) + .with( + { + region: instance_of(String), + role_arn: "arn:aws:iam::#{account}:role/another-role", + role_session_name: instance_of(String) + } + ) + .once role_assumer.assume_role(account, role, &my_block) role_assumer.assume_role(account, 'another-role', &my_block) diff --git a/spec/stack_master/security_group_finder_spec.rb b/spec/stack_master/security_group_finder_spec.rb index 39779941..678dbeba 100644 --- a/spec/stack_master/security_group_finder_spec.rb +++ b/spec/stack_master/security_group_finder_spec.rb @@ -19,19 +19,23 @@ end context "one sg match" do - let(:security_groups) { [ - double(id: 'sg-a7d2ccc0') - ] } + let(:security_groups) { + [ + double(id: 'sg-a7d2ccc0') + ] + } it "returns the id" do expect(finder.find(group_name)).to eq 'sg-a7d2ccc0' end end context "more than one sg matches" do - let(:security_groups) { [ - double(id: 'sg-a7d2ccc0'), - double(id: 'sg-a7d2ccc2'), - ] } + let(:security_groups) { + [ + double(id: 'sg-a7d2ccc0'), + double(id: 'sg-a7d2ccc2'), + ] + } it "returns the id" do err = StackMaster::SecurityGroupFinder::MultipleSecurityGroupsFound expect { finder.find(group_name) }.to raise_error(err) diff --git a/spec/stack_master/sns_topic_finder_spec.rb b/spec/stack_master/sns_topic_finder_spec.rb index 97e95317..c206a5cc 100644 --- a/spec/stack_master/sns_topic_finder_spec.rb +++ b/spec/stack_master/sns_topic_finder_spec.rb @@ -1,5 +1,4 @@ RSpec.describe StackMaster::SnsTopicFinder do - subject(:finder) { described_class.new(region) } let(:region) { 'us-east-1' } let(:topics) do diff --git a/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb index 474c2b95..b0b31286 100644 --- a/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/allowed_pattern_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::AllowedPatternValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} does not match allowed_pattern:#{definition[:allowed_pattern]}" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} does not match allowed_pattern:#{definition[:allowed_pattern]}" + } + end context 'string validation' do - let(:definition) { {type: :string, allowed_pattern: '^a'} } + let(:definition) { { type: :string, allowed_pattern: '^a' } } validate_valid_parameter('a') validate_valid_parameter(['a']) validate_invalid_parameter('b', ['b']) @@ -13,24 +16,24 @@ end context 'string validation with default' do - let(:definition) { {type: :string, allowed_pattern: '^a', default: 'a'} } + let(:definition) { { type: :string, allowed_pattern: '^a', default: 'a' } } validate_valid_parameter(nil) end context 'string validation with multiple' do - let(:definition) { {type: :string, allowed_pattern: '^a', multiple: true} } + let(:definition) { { type: :string, allowed_pattern: '^a', multiple: true } } validate_valid_parameter('a,ab') validate_invalid_parameter('a,,ab', ['']) validate_invalid_parameter('a, ,ab', ['']) end context 'string validation with multiple default values' do - let(:definition) { {type: :string, allowed_pattern: '^a', multiple: true, default:'a,a'} } + let(:definition) { { type: :string, allowed_pattern: '^a', multiple: true, default: 'a,a' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number, allowed_pattern: '^1'} } + let(:definition) { { type: :number, allowed_pattern: '^1' } } validate_valid_parameter(1) validate_valid_parameter('1') validate_valid_parameter([1]) @@ -40,8 +43,8 @@ end context 'validation with default value' do - let(:definition) { {type: :number, allowed_pattern: '^1', default: '1'} } + let(:definition) { { type: :number, allowed_pattern: '^1', default: '1' } } validate_valid_parameter(nil) end end -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb index 8a12c13b..f98f5a2d 100644 --- a/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/allowed_values_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::AllowedValuesValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} is not in allowed_values:#{definition[:allowed_values]}" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} is not in allowed_values:#{definition[:allowed_values]}" + } + end context 'string validation' do - let(:definition) { {type: :string, allowed_values: ['a']} } + let(:definition) { { type: :string, allowed_values: ['a'] } } validate_valid_parameter('a') validate_valid_parameter(['a']) validate_invalid_parameter('b', ['b']) @@ -13,24 +16,24 @@ end context 'string validation with default' do - let(:definition) { {type: :string, allowed_values: ['a'], default:'a'} } + let(:definition) { { type: :string, allowed_values: ['a'], default: 'a' } } validate_valid_parameter(nil) end context 'string validation with multiple' do - let(:definition) { {type: :string, allowed_values: ['a'], multiple: true} } + let(:definition) { { type: :string, allowed_values: ['a'], multiple: true } } validate_valid_parameter('a,a') - validate_invalid_parameter( 'a,, a', ['']) - validate_invalid_parameter( 'a,,b', ['', 'b']) + validate_invalid_parameter('a,, a', ['']) + validate_invalid_parameter('a,,b', ['', 'b']) end context 'string validation with multiple default values' do - let(:definition) { {type: :string, allowed_values: ['a'], multiple: true, default: 'a,a'} } + let(:definition) { { type: :string, allowed_values: ['a'], multiple: true, default: 'a,a' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number, allowed_values: [1]} } + let(:definition) { { type: :number, allowed_values: [1] } } validate_valid_parameter(1) validate_valid_parameter('1') validate_valid_parameter([1]) @@ -40,8 +43,8 @@ end context 'numerical validation with default value' do - let(:definition) { {type: :number, allowed_values: [1], default: 1} } + let(:definition) { { type: :number, allowed_values: [1], default: 1 } } validate_valid_parameter(nil) end end -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb index 99610b59..6a6a2b8b 100644 --- a/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/definitions_validator_spec.rb @@ -1,36 +1,30 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::DefinitionsValidator do - describe '#validate' do + let(:key) { :key } + let(:definition) { { key: { type: type } } } - let(:key) {:key} - let(:definition){ {key: {type: type}} } - - subject {described_class.new(definition)} + subject { described_class.new(definition) } [:string, :number].each do |type| - context "with :#{type} type definition" do - - let(:type) {type} + let(:type) { type } it 'should not raise an exception' do - expect {subject.validate}.to_not raise_error + expect { subject.validate }.to_not raise_error end - end - end context 'with other type definition' do - - let(:type) {:other} + let(:type) { :other } it 'should not raise an exception' do - expect {subject.validate}.to raise_error(ArgumentError, "Unknown compile time parameter type: #{key}:#{type} valid types are #{[:string, :number]}") + expect { subject.validate } + .to raise_error( + ArgumentError, + "Unknown compile time parameter type: #{key}:#{type} valid types are #{[:string, :number]}" + ) end - end - end - -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb index 453b4bf3..9332a725 100644 --- a/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/empty_validator_spec.rb @@ -1,11 +1,10 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::EmptyValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, _definition) { "#{name} cannot contain empty parameters:#{error.inspect}" } } + let(:error_message) { ->(error, _definition) { "#{name} cannot contain empty parameters:#{error.inspect}" } } context 'string validation' do - let(:definition) { {type: :string} } + let(:definition) { { type: :string } } validate_valid_parameter('a') validate_valid_parameter(['a']) validate_invalid_parameter(nil, nil) @@ -13,23 +12,23 @@ end context 'string validation with default' do - let(:definition) { {type: :string, default: 'a'} } + let(:definition) { { type: :string, default: 'a' } } validate_valid_parameter(nil) end context 'string validation with multiples' do - let(:definition) { {type: :string, multiple: true} } + let(:definition) { { type: :string, multiple: true } } validate_valid_parameter('a,b') validate_valid_parameter('a,,b') end context 'string validation with multiples and defaults' do - let(:definition) { {type: :string, multiple: true, default: 'a,b'} } + let(:definition) { { type: :string, multiple: true, default: 'a,b' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number} } + let(:definition) { { type: :number } } validate_valid_parameter(1) validate_valid_parameter('1') validate_valid_parameter([1]) @@ -40,7 +39,7 @@ end context 'numerical validation with default' do - let(:definition) { {type: :number, default: '1'} } + let(:definition) { { type: :number, default: '1' } } validate_valid_parameter(nil) end end diff --git a/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb index 56a914b3..eff103b3 100644 --- a/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/max_length_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::MaxLengthValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} must not exceed max_length:#{definition[:max_length]} characters" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} must not exceed max_length:#{definition[:max_length]} characters" + } + end context 'string validation' do - let(:definition) { {type: :string, max_length: 1} } + let(:definition) { { type: :string, max_length: 1 } } validate_valid_parameter('a') validate_valid_parameter(['a']) validate_invalid_parameter('ab', ['ab']) @@ -13,24 +16,24 @@ end context 'string validation with default value' do - let(:definition) { {type: :string, max_length: 1, default: 'a'} } + let(:definition) { { type: :string, max_length: 1, default: 'a' } } validate_valid_parameter(nil) end context 'string validation with multiples' do - let(:definition) { {type: :string, max_length: 1, multiple: true} } + let(:definition) { { type: :string, max_length: 1, multiple: true } } validate_valid_parameter('a,a') validate_valid_parameter('a,,a') validate_invalid_parameter('a,, ab', ['ab']) end context 'string validation wtih multiples and default' do - let(:definition) { {type: :string, max_length: 1, multiple: true, default: 'a,a'} } + let(:definition) { { type: :string, max_length: 1, multiple: true, default: 'a,a' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number, max_length: 1} } + let(:definition) { { type: :number, max_length: 1 } } validate_valid_parameter('ab') end end diff --git a/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb index 6d626e43..66647e29 100644 --- a/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/max_size_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::MaxSizeValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} must not be greater than max_size:#{definition[:max_size]}" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} must not be greater than max_size:#{definition[:max_size]}" + } + end context 'numerical validation' do - let(:definition) { {type: :number, max_size: 1} } + let(:definition) { { type: :number, max_size: 1 } } validate_valid_parameter(1) validate_valid_parameter('1') validate_valid_parameter([1]) @@ -15,13 +18,13 @@ end context 'numerical validation with default' do - let(:definition) { {type: :number, max_size: 1, default: 1} } + let(:definition) { { type: :number, max_size: 1, default: 1 } } validate_valid_parameter(nil) end context 'string validation' do - let(:definition) { {type: :string, max_size: 1} } + let(:definition) { { type: :string, max_size: 1 } } validate_valid_parameter(2) end end -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb index 36c7a0a7..400ccd05 100644 --- a/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/min_length_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::MinLengthValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} must be at least min_length:#{definition[:min_length]} characters" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} must be at least min_length:#{definition[:min_length]} characters" + } + end context 'string validation' do - let(:definition) { {type: :string, min_length: 2} } + let(:definition) { { type: :string, min_length: 2 } } validate_valid_parameter('ab') validate_valid_parameter(['ab']) validate_invalid_parameter('a', ['a']) @@ -13,23 +16,23 @@ end context 'string validation with default value' do - let(:definition) { {type: :string, min_length: 2, default: 'ab'} } + let(:definition) { { type: :string, min_length: 2, default: 'ab' } } validate_valid_parameter(nil) end context 'string validation with multiples' do - let(:definition) { {type: :string, min_length: 2, multiple: true} } + let(:definition) { { type: :string, min_length: 2, multiple: true } } validate_valid_parameter('ab,cd') validate_invalid_parameter('a,, cd', ['a', '']) end context 'string validation with multiples and default' do - let(:definition) { {type: :string, min_length: 2, multiple: true, default: 'ab,cd'} } + let(:definition) { { type: :string, min_length: 2, multiple: true, default: 'ab,cd' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number, min_length: 2} } + let(:definition) { { type: :number, min_length: 2 } } validate_valid_parameter('a') end end diff --git a/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb index 4a158d52..1e14ae06 100644 --- a/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/min_size_validator_spec.rb @@ -1,11 +1,14 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::MinSizeValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, definition) { "#{name}:#{error} must not be lesser than min_size:#{definition[:min_size]}" } } + let(:error_message) do + lambda { |error, definition| + "#{name}:#{error} must not be lesser than min_size:#{definition[:min_size]}" + } + end context 'numerical validation' do - let(:definition) { {type: :number, min_size: 1} } + let(:definition) { { type: :number, min_size: 1 } } validate_valid_parameter(1) validate_valid_parameter('1') validate_valid_parameter([1]) @@ -15,14 +18,13 @@ end context 'numerical validation with default value' do - let(:definition) { {type: :number, min_size: 1, default: 1} } + let(:definition) { { type: :number, min_size: 1, default: 1 } } validate_valid_parameter(nil) end context 'string validation' do - let(:definition) { {type: :string, min_size: 1} } + let(:definition) { { type: :string, min_size: 1 } } validate_valid_parameter(0) end - end end diff --git a/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb index a12c4527..d71ba0cd 100644 --- a/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/number_validator_spec.rb @@ -1,11 +1,10 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::NumberValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, _definition) { "#{name}:#{error} are not Numbers" } } + let(:error_message) { ->(error, _definition) { "#{name}:#{error} are not Numbers" } } context 'numerical validation' do - let(:definition) { {type: :number} } + let(:definition) { { type: :number } } validate_valid_parameter(1) validate_valid_parameter(['1']) validate_invalid_parameter(['1.'], ['1.']) @@ -15,12 +14,12 @@ end context 'numerical validation with default' do - let(:definition) { {type: :number, default: 1} } + let(:definition) { { type: :number, default: 1 } } validate_valid_parameter(nil) end context 'numerical validation with multiples' do - let(:definition) { {type: :number, multiple: true} } + let(:definition) { { type: :number, multiple: true } } validate_valid_parameter('1,2') validate_valid_parameter([1, 2]) validate_invalid_parameter('1,1.', ['1.']) @@ -28,14 +27,13 @@ end context 'numerical validation with multiples and default' do - let(:definition) { {type: :number, multiple: true, default: '1,2'} } + let(:definition) { { type: :number, multiple: true, default: '1,2' } } validate_valid_parameter(nil) end context 'string validation' do - let(:definition) { {type: :string} } + let(:definition) { { type: :string } } validate_valid_parameter('a') end - end end diff --git a/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb index e1913761..7d4659c8 100644 --- a/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/parameters_validator_spec.rb @@ -1,25 +1,30 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::ParametersValidator do + let(:definitions) { { ip: { type: :string } } } + let(:parameters) { { 'Ip' => '10.0.0.0' } } + let(:value_validator_factory) { instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory) } + let(:value_validator) { instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidator) } - let(:definitions) {{ip: {type: :string}}} - let(:parameters) {{'Ip' => '10.0.0.0'}} - let(:value_validator_factory) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory)} - let(:value_validator) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueValidator)} - - subject {described_class.new(definitions, parameters)} + subject { described_class.new(definitions, parameters) } before(:each) do allow(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory) - .to receive(:new).and_return(value_validator_factory) + .to receive(:new) + .and_return(value_validator_factory) allow(value_validator_factory) - .to receive(:build).and_return([value_validator]) - allow(value_validator).to receive(:validate) - allow(value_validator).to receive(:is_valid).and_return(true) + .to receive(:build) + .and_return([value_validator]) + allow(value_validator) + .to receive(:validate) + allow(value_validator) + .to receive(:is_valid) + .and_return(true) end describe '#validate' do - it('should initialise the ValueValidatorFactory') do - expect(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory).to receive(:new).with(:ip, {type: :string}, '10.0.0.0') + expect(StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory) + .to receive(:new) + .with(:ip, { type: :string }, '10.0.0.0') subject.validate end @@ -34,20 +39,17 @@ end context 'when the validators are valid' do - before(:each) do allow(value_validator).to receive(:is_valid).and_return(true) end it('should not raise any error') do - expect{subject.validate}.to_not raise_error + expect { subject.validate }.to_not raise_error end - end context 'when the validators are invalid' do - - let(:error){'error'} + let(:error) { 'error' } before(:each) do allow(value_validator).to receive(:is_valid).and_return(false) @@ -55,11 +57,8 @@ end it('should raise an error') do - expect {subject.validate}.to raise_error(ArgumentError, "Invalid compile time parameter: #{error}") + expect { subject.validate }.to raise_error(ArgumentError, "Invalid compile time parameter: #{error}") end - end - end - -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb b/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb index 7aafa619..3d5ae25a 100644 --- a/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/state_builder_spec.rb @@ -1,28 +1,30 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::StateBuilder do + let(:definitions) { { ip: { type: :string }, size: { type: :number } } } + let(:ip) { '10.0.0.0' } + let(:size) { nil } + let(:parameters) { { 'Ip' => ip } } + let(:ip_builder) { instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder) } + let(:size_builder) { instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder) } - let(:definitions) {{ip: {type: :string}, size: {type: :number}}} - let(:ip) {'10.0.0.0'} - let(:size) {nil} - let(:parameters) {{'Ip' => ip}} - let(:ip_builder) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder)} - let(:size_builder) {instance_double(StackMaster::SparkleFormation::CompileTime::ValueBuilder)} - - subject {described_class.new(definitions, parameters)} + subject { described_class.new(definitions, parameters) } before(:each) do - allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder).to receive(:new).with({type: :string}, ip).and_return(ip_builder) - allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder).to receive(:new).with({type: :number}, size).and_return(size_builder) + allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder) + .to receive(:new) + .with({ type: :string }, ip) + .and_return(ip_builder) + allow(StackMaster::SparkleFormation::CompileTime::ValueBuilder) + .to receive(:new) + .with({ type: :number }, size) + .and_return(size_builder) allow(ip_builder).to receive(:build).and_return(ip) allow(size_builder).to receive(:build).and_return(size) end describe '#build' do - it 'should create state' do - expected = {ip: '10.0.0.0', size: nil} + expected = { ip: '10.0.0.0', size: nil } expect(subject.build).to eq(expected) end - end - end diff --git a/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb b/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb index 19b19259..24230823 100644 --- a/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/string_validator_spec.rb @@ -1,34 +1,33 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::StringValidator do - describe '#validate' do let(:name) { 'name' } - let(:error_message) { -> (error, _definition) { "#{name}:#{error} are not Strings" } } + let(:error_message) { ->(error, _definition) { "#{name}:#{error} are not Strings" } } context 'string validation' do - let(:definition) { {type: :string} } + let(:definition) { { type: :string } } validate_valid_parameter('a') validate_valid_parameter(['']) validate_invalid_parameter({}, [{}]) end context 'string validation default' do - let(:definition) { {type: :string, default: 'a'} } + let(:definition) { { type: :string, default: 'a' } } validate_valid_parameter(nil) end context 'string validation with multiples' do - let(:definition) { {type: :string, multiple: true} } + let(:definition) { { type: :string, multiple: true } } validate_valid_parameter('a,b') validate_invalid_parameter([{}], [{}]) end context 'string validation with multiples and default' do - let(:definition) { {type: :string, multiple: true, default: 'a,a'} } + let(:definition) { { type: :string, multiple: true, default: 'a,a' } } validate_valid_parameter(nil) end context 'numerical validation' do - let(:definition) { {type: :number} } + let(:definition) { { type: :number } } validate_valid_parameter(1) end end diff --git a/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb b/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb index 096a1eaf..ba0e1d03 100644 --- a/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/value_build_spec.rb @@ -1,40 +1,37 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::ValueBuilder do - scenarios= [ - {definition: {type: :string}, parameter: nil, expected: nil}, - {definition: {type: :string}, parameter: 'a', expected: 'a'}, - {definition: {type: :string}, parameter: ['a'], expected: ['a']}, + scenarios = [ + { definition: { type: :string }, parameter: nil, expected: nil }, + { definition: { type: :string }, parameter: 'a', expected: 'a' }, + { definition: { type: :string }, parameter: ['a'], expected: ['a'] }, - {definition: {type: :string, default: 'a'}, parameter: nil, expected: 'a'}, + { definition: { type: :string, default: 'a' }, parameter: nil, expected: 'a' }, - {definition: {type: :string, multiple: true}, parameter: 'a', expected: ['a']}, - {definition: {type: :string, multiple: true}, parameter: 'a,b', expected: ['a', 'b']}, - {definition: {type: :string, multiple: true}, parameter: 'a, b', expected: ['a', 'b']}, + { definition: { type: :string, multiple: true }, parameter: 'a', expected: ['a'] }, + { definition: { type: :string, multiple: true }, parameter: 'a,b', expected: ['a', 'b'] }, + { definition: { type: :string, multiple: true }, parameter: 'a, b', expected: ['a', 'b'] }, - {definition: {type: :string, multiple: true, default: 'a'}, parameter: nil, expected: ['a']}, + { definition: { type: :string, multiple: true, default: 'a' }, parameter: nil, expected: ['a'] }, - {definition: {type: :number}, parameter: nil, expected: nil}, - {definition: {type: :number}, parameter: 1, expected: 1}, - {definition: {type: :number}, parameter: '1', expected: 1}, - {definition: {type: :number}, parameter: [1], expected: [1]}, - {definition: {type: :number}, parameter: ['1'], expected: [1]}, + { definition: { type: :number }, parameter: nil, expected: nil }, + { definition: { type: :number }, parameter: 1, expected: 1 }, + { definition: { type: :number }, parameter: '1', expected: 1 }, + { definition: { type: :number }, parameter: [1], expected: [1] }, + { definition: { type: :number }, parameter: ['1'], expected: [1] }, - {definition: {type: :number, default: '1'}, parameter: nil, expected: 1}, + { definition: { type: :number, default: '1' }, parameter: nil, expected: 1 }, - {definition: {type: :number, multiple: true}, parameter: 1, expected: 1}, - {definition: {type: :number, multiple: true}, parameter: '1', expected: [1]}, - {definition: {type: :number, multiple: true}, parameter: '1,2', expected: [1,2]}, - {definition: {type: :number, multiple: true}, parameter: '1, 2', expected: [1,2]}, + { definition: { type: :number, multiple: true }, parameter: 1, expected: 1 }, + { definition: { type: :number, multiple: true }, parameter: '1', expected: [1] }, + { definition: { type: :number, multiple: true }, parameter: '1,2', expected: [1, 2] }, + { definition: { type: :number, multiple: true }, parameter: '1, 2', expected: [1, 2] }, - {definition: {type: :number, multiple: true, default: '1'}, parameter: nil, expected: [1]} + { definition: { type: :number, multiple: true, default: '1' }, parameter: nil, expected: [1] } ] describe '#build' do - scenarios.each do |scenario| - - description = scenario.clone.tap {|clone| clone.delete(:expected)} + description = scenario.clone.tap { |clone| clone.delete(:expected) } context "when #{description}" do - definition = scenario[:definition] parameter = scenario[:parameter] expected = scenario[:expected] @@ -42,11 +39,7 @@ it("should have a value of #{expected}") do expect(described_class.new(definition, parameter).build).to eq expected end - end - end - end - -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb b/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb index 17ed58e2..7e0ce14f 100644 --- a/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb +++ b/spec/stack_master/sparkle_formation/compile_time/value_validator_factory_spec.rb @@ -1,32 +1,29 @@ RSpec.describe StackMaster::SparkleFormation::CompileTime::ValueValidatorFactory do + let(:name) { :ip } + let(:definition) { { type: :string } } + let(:parameter) { { 'Ip' => '10.0.0.0' } } - let(:name) {:ip} - let(:definition) {{type: :string}} - let(:parameter) {{'Ip' => '10.0.0.0'}} - - subject {described_class.new(name, definition, parameter)} + subject { described_class.new(name, definition, parameter) } describe '#build' do - validators = [ - StackMaster::SparkleFormation::CompileTime::EmptyValidator, - StackMaster::SparkleFormation::CompileTime::StringValidator, - StackMaster::SparkleFormation::CompileTime::NumberValidator, - StackMaster::SparkleFormation::CompileTime::AllowedValuesValidator, - StackMaster::SparkleFormation::CompileTime::AllowedPatternValidator, - StackMaster::SparkleFormation::CompileTime::MaxLengthValidator, - StackMaster::SparkleFormation::CompileTime::MinLengthValidator, - StackMaster::SparkleFormation::CompileTime::MaxSizeValidator, - StackMaster::SparkleFormation::CompileTime::MinSizeValidator] - - after(:each){subject.build} + StackMaster::SparkleFormation::CompileTime::EmptyValidator, + StackMaster::SparkleFormation::CompileTime::StringValidator, + StackMaster::SparkleFormation::CompileTime::NumberValidator, + StackMaster::SparkleFormation::CompileTime::AllowedValuesValidator, + StackMaster::SparkleFormation::CompileTime::AllowedPatternValidator, + StackMaster::SparkleFormation::CompileTime::MaxLengthValidator, + StackMaster::SparkleFormation::CompileTime::MinLengthValidator, + StackMaster::SparkleFormation::CompileTime::MaxSizeValidator, + StackMaster::SparkleFormation::CompileTime::MinSizeValidator + ] + + after(:each) { subject.build } validators.each do |validator| - it "should build a #{validator} with correct parameters" do expect(validator).to receive(:new).with(name, definition, parameter) end - end it 'should build in the correct order' do @@ -34,7 +31,5 @@ expect(validator).to receive(:new).ordered end end - end - -end \ No newline at end of file +end diff --git a/spec/stack_master/sparkle_formation/template_file_spec.rb b/spec/stack_master/sparkle_formation/template_file_spec.rb index 02b2fbeb..4c10f08a 100644 --- a/spec/stack_master/sparkle_formation/template_file_spec.rb +++ b/spec/stack_master/sparkle_formation/template_file_spec.rb @@ -2,17 +2,17 @@ RSpec.describe SparkleFormation::SparkleAttribute::Aws, '#user_data_file!' do let(:user_data) do - <<-EOS -#!/bin/bash + <<~EOS + #!/bin/bash -REGION=<%= region! %> -echo $REGION -<%= ref!(:test) %> <%= ref!(:test_2) %> -<%= has_var?(:test) ? "echo 'yes'" : "echo 'no'" %> + REGION=<%= region! %> + echo $REGION + <%= ref!(:test) %> <%= ref!(:test_2) %> + <%= has_var?(:test) ? "echo 'yes'" : "echo 'no'" %> EOS end let(:expected_hash) do - {"Fn::Base64"=>{"Fn::Join"=>["", ["#!/bin/bash\n", "\n", "REGION=", {"Ref"=>"AWS::Region"}, "\n", "echo $REGION\n", {"Ref"=>"Test"}, " ", {"Ref"=>"Test2"}, "\n", "echo 'no'", "\n"]]}} + { "Fn::Base64" => { "Fn::Join" => ["", ["#!/bin/bash\n", "\n", "REGION=", { "Ref" => "AWS::Region" }, "\n", "echo $REGION\n", { "Ref" => "Test" }, " ", { "Ref" => "Test2" }, "\n", "echo 'no'", "\n"]] } } end before do @@ -41,14 +41,14 @@ context 'with custom vars' do let(:user_data) do - <<-EOS -#!/bin/bash -<%= my_custom_var %> -<%= has_var?(:my_custom_var) ? "yes" : "no" %> + <<~EOS + #!/bin/bash + <%= my_custom_var %> + <%= has_var?(:my_custom_var) ? "yes" : "no" %> EOS end let(:expected_hash) do - {"Fn::Base64"=>{"Fn::Join"=>["", ["#!/bin/bash\n", "test_var", "\n", "yes", "\n"]]}} + { "Fn::Base64" => { "Fn::Join" => ["", ["#!/bin/bash\n", "test_var", "\n", "yes", "\n"]] } } end it 'compiles the file and returns a joined version' do @@ -72,29 +72,23 @@ context 'with nested templates' do let(:inner_user_data) do - <<-EOS -REGION=<%= region! %> -<%= test1 %> -<%= has_var?(:test2) ? 'yes' : 'no' %> + <<~EOS + REGION=<%= region! %> + <%= test1 %> + <%= has_var?(:test2) ? 'yes' : 'no' %> EOS end let(:outer_user_data) do - <<-EOS -#!/bin/bash -<%= test1 %> <%= test2 %> -<%= render 'inner.sh.erb', test1: 'inner1' %> + <<~EOS + #!/bin/bash + <%= test1 %> <%= test2 %> + <%= render 'inner.sh.erb', test1: 'inner1' %> EOS end let(:expected_hash) do - {"Fn::Base64"=>{"Fn::Join"=>["", [ - "#!/bin/bash\n", - "outer1", " ", "outer2", "\n", - "REGION=", {"Ref"=>"AWS::Region"}, "\n", - "inner1", "\n", - "no", "\n", "\n" - ]]}} + { "Fn::Base64" => { "Fn::Join" => ["", ["#!/bin/bash\n", "outer1", " ", "outer2", "\n", "REGION=", { "Ref" => "AWS::Region" }, "\n", "inner1", "\n", "no", "\n", "\n"]] } } end before do @@ -111,13 +105,13 @@ RSpec.describe SparkleFormation::SparkleAttribute::Aws, '#joined_file!' do let(:config) do - <<-EOS -variable=<%= ref!(:test) %> + <<~EOS + variable=<%= ref!(:test) %> EOS end let(:expected_hash) do - {"Fn::Join"=>["", ["variable=", {"Ref"=>"Test"}, "\n"]]} + { "Fn::Join" => ["", ["variable=", { "Ref" => "Test" }, "\n"]] } end before do diff --git a/spec/stack_master/sso_group_id_finder_spec.rb b/spec/stack_master/sso_group_id_finder_spec.rb index 7a34db74..04bbaa78 100644 --- a/spec/stack_master/sso_group_id_finder_spec.rb +++ b/spec/stack_master/sso_group_id_finder_spec.rb @@ -8,7 +8,7 @@ let(:aws_client) { instance_double(Aws::IdentityStore::Client) } subject(:finder) do - allow(Aws::IdentityStore::Client).to receive(:new).with({region: region}).and_return(aws_client) + allow(Aws::IdentityStore::Client).to receive(:new).with({ region: region }).and_return(aws_client) described_class.new end @@ -22,15 +22,20 @@ group_id = 'abc-123-group-id' response = double(group_id: group_id) - expect(aws_client).to receive(:get_group_id).with({ - identity_store_id: identity_store_id, - alternate_identifier: { - unique_attribute: { - attribute_path: 'displayName', - attribute_value: group_name + expect(aws_client) + .to receive(:get_group_id) + .with( + { + identity_store_id: identity_store_id, + alternate_identifier: { + unique_attribute: { + attribute_path: 'displayName', + attribute_value: group_name + } + } } - } - }).and_return(response) + ) + .and_return(response) expect(finder.find(reference)).to eq(group_id) end @@ -45,9 +50,8 @@ expect(aws_client).to receive(:get_group_id).and_raise(error) - expect { - finder.find(reference) - }.to raise_error(StackMaster::SsoGroupIdFinder::SsoGroupNotFound, /No group with name #{group_name} found/) + expect { finder.find(reference) } + .to raise_error(StackMaster::SsoGroupIdFinder::SsoGroupNotFound, /No group with name #{group_name} found/) end end @@ -55,20 +59,25 @@ let(:reference_without_region) { "#{identity_store_id}/#{group_name}" } it 'uses the fallback region from cloud_formation_driver' do - allow(Aws::IdentityStore::Client).to receive(:new).with({region: region}).and_return(aws_client) + allow(Aws::IdentityStore::Client).to receive(:new).with({ region: region }).and_return(aws_client) group_id = 'fallback-region-group-id' response = double(group_id: group_id) - expect(aws_client).to receive(:get_group_id).with({ - identity_store_id: identity_store_id, - alternate_identifier: { - unique_attribute: { - attribute_path: 'displayName', - attribute_value: group_name + expect(aws_client) + .to receive(:get_group_id) + .with( + { + identity_store_id: identity_store_id, + alternate_identifier: { + unique_attribute: { + attribute_path: 'displayName', + attribute_value: group_name + } + } } - } - }).and_return(response) + ) + .and_return(response) expect(finder.find(reference_without_region)).to eq(group_id) end @@ -76,9 +85,8 @@ context 'when input is not a string' do it 'raises ArgumentError' do - expect { - finder.find(123) - }.to raise_error(ArgumentError, /Sso group lookup parameter must be in the form/) + expect { finder.find(123) } + .to raise_error(ArgumentError, /Sso group lookup parameter must be in the form/) end end @@ -86,9 +94,8 @@ it 'raises ArgumentError' do invalid_reference = 'badformat' - expect { - finder.find(invalid_reference) - }.to raise_error(ArgumentError, /Sso group lookup parameter must be in the form/) + expect { finder.find(invalid_reference) } + .to raise_error(ArgumentError, /Sso group lookup parameter must be in the form/) end end end diff --git a/spec/stack_master/stack_definition_spec.rb b/spec/stack_master/stack_definition_spec.rb index f0af5f07..3e901552 100644 --- a/spec/stack_master/stack_definition_spec.rb +++ b/spec/stack_master/stack_definition_spec.rb @@ -6,13 +6,14 @@ template: template, tags: tags, base_dir: base_dir, - parameter_files: parameter_files) + parameter_files: parameter_files + ) end let(:region) { 'us-east-1' } let(:stack_name) { 'stack_name' } let(:template) { 'template.json' } - let(:tags) { {'environment' => 'production'} } + let(:tags) { { 'environment' => 'production' } } let(:base_dir) { '/base_dir' } let(:parameter_files) { nil } @@ -37,29 +38,35 @@ end it 'has default and region specific parameter file locations' do - expect(stack_definition.all_parameter_files).to eq([ - "/base_dir/parameters/#{stack_name}.yaml", - "/base_dir/parameters/#{stack_name}.yml", - "/base_dir/parameters/#{region}/#{stack_name}.yaml", - "/base_dir/parameters/#{region}/#{stack_name}.yml", - ]) + expect(stack_definition.all_parameter_files).to eq( + [ + "/base_dir/parameters/#{stack_name}.yaml", + "/base_dir/parameters/#{stack_name}.yml", + "/base_dir/parameters/#{region}/#{stack_name}.yaml", + "/base_dir/parameters/#{region}/#{stack_name}.yml", + ] + ) end it 'returns all globs' do - expect(stack_definition.parameter_file_globs).to eq([ - "/base_dir/parameters/#{stack_name}.y*ml", - "/base_dir/parameters/#{region}/#{stack_name}.y*ml", - ]) + expect(stack_definition.parameter_file_globs).to eq( + [ + "/base_dir/parameters/#{stack_name}.y*ml", + "/base_dir/parameters/#{region}/#{stack_name}.y*ml", + ] + ) end context 'given a stack_name with a dash' do let(:stack_name) { 'stack-name' } it 'returns globs supporting dashes and underscores in the parameter filenames' do - expect(stack_definition.parameter_file_globs).to eq([ - "/base_dir/parameters/stack[-_]name.y*ml", - "/base_dir/parameters/#{region}/stack[-_]name.y*ml", - ]) + expect(stack_definition.parameter_file_globs).to eq( + [ + "/base_dir/parameters/stack[-_]name.y*ml", + "/base_dir/parameters/#{region}/stack[-_]name.y*ml", + ] + ) end end @@ -77,33 +84,39 @@ end it 'includes a parameter lookup dir for it' do - expect(stack_definition.all_parameter_files).to eq([ - "/base_dir/parameters/#{stack_name}.yaml", - "/base_dir/parameters/#{stack_name}.yml", - "/base_dir/parameters/#{region}/#{stack_name}.yaml", - "/base_dir/parameters/#{region}/#{stack_name}.yml", - "/base_dir/parameters/production/#{stack_name}.yaml", - "/base_dir/parameters/production/#{stack_name}.yml", - ]) + expect(stack_definition.all_parameter_files).to eq( + [ + "/base_dir/parameters/#{stack_name}.yaml", + "/base_dir/parameters/#{stack_name}.yml", + "/base_dir/parameters/#{region}/#{stack_name}.yaml", + "/base_dir/parameters/#{region}/#{stack_name}.yml", + "/base_dir/parameters/production/#{stack_name}.yaml", + "/base_dir/parameters/production/#{stack_name}.yml", + ] + ) end it 'returns all globs' do - expect(stack_definition.parameter_file_globs).to eq([ - "/base_dir/parameters/#{stack_name}.y*ml", - "/base_dir/parameters/#{region}/#{stack_name}.y*ml", - "/base_dir/parameters/production/#{stack_name}.y*ml", - ]) + expect(stack_definition.parameter_file_globs).to eq( + [ + "/base_dir/parameters/#{stack_name}.y*ml", + "/base_dir/parameters/#{region}/#{stack_name}.y*ml", + "/base_dir/parameters/production/#{stack_name}.y*ml", + ] + ) end context 'given a stack_name with a dash' do let(:stack_name) { 'stack-name' } it 'returns globs supporting dashes and underscores in the parameter filenames' do - expect(stack_definition.parameter_file_globs).to eq([ - "/base_dir/parameters/stack[-_]name.y*ml", - "/base_dir/parameters/#{region}/stack[-_]name.y*ml", - "/base_dir/parameters/production/stack[-_]name.y*ml", - ]) + expect(stack_definition.parameter_file_globs).to eq( + [ + "/base_dir/parameters/stack[-_]name.y*ml", + "/base_dir/parameters/#{region}/stack[-_]name.y*ml", + "/base_dir/parameters/production/stack[-_]name.y*ml", + ] + ) end end end diff --git a/spec/stack_master/stack_differ_spec.rb b/spec/stack_master/stack_differ_spec.rb index 72cf7b4d..229458b4 100644 --- a/spec/stack_master/stack_differ_spec.rb +++ b/spec/stack_master/stack_differ_spec.rb @@ -3,24 +3,36 @@ let(:current_body) { '{}' } let(:proposed_body) { "{\"a\": 1}" } let(:current_params) { Hash.new } - let(:proposed_params) { { 'param1' => 'hello'} } - let(:stack) { StackMaster::Stack.new(stack_name: stack_name, - region: region, - stack_id: 123, - template_body: current_body, - template_format: :json, - parameters: current_params) } - let(:proposed_stack) { StackMaster::Stack.new(stack_name: stack_name, - region: region, - parameters: proposed_params, - template_body: proposed_body, - template_format: :json) } + let(:proposed_params) { { 'param1' => 'hello' } } + let(:stack) { + StackMaster::Stack.new( + stack_name: stack_name, + region: region, + stack_id: 123, + template_body: current_body, + template_format: :json, + parameters: current_params + ) + } + let(:proposed_stack) { + StackMaster::Stack.new( + stack_name: stack_name, + region: region, + parameters: proposed_params, + template_body: proposed_body, + template_format: :json + ) + } let(:stack_name) { 'myapp-vpc' } let(:region) { 'us-east-1' } describe "#proposed_parameters" do - let(:current_params) { { 'param1' => 'hello', - 'param2' => '****'} } + let(:current_params) { + { + 'param1' => 'hello', + 'param2' => '****' + } + } it "stars out noecho params" do expect(differ.proposed_parameters).to eq "---\nparam1: hello\nparam2: \"****\"\n" end diff --git a/spec/stack_master/stack_events/fetcher_spec.rb b/spec/stack_master/stack_events/fetcher_spec.rb index 8f0a2588..847e9fd8 100644 --- a/spec/stack_master/stack_events/fetcher_spec.rb +++ b/spec/stack_master/stack_events/fetcher_spec.rb @@ -5,14 +5,24 @@ before do allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf) allow(StackMaster::StackEvents::Streamer).to receive(:stream) - allow(StackMaster::PagedResponseAccumulator).to receive(:call).with(StackMaster.cloud_formation_driver, :describe_stack_events, { stack_name: stack_name }, :stack_events).and_return(OpenStruct.new(stack_events: events)) + allow(StackMaster::PagedResponseAccumulator) + .to receive(:call) + .with( + StackMaster.cloud_formation_driver, + :describe_stack_events, + { stack_name: stack_name }, + :stack_events + ) + .and_return(OpenStruct.new(stack_events: events)) end context 'with 2 stack events' do - let(:events) { [ - OpenStruct.new(event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now), - OpenStruct.new(event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now) - ] } + let(:events) { + [ + OpenStruct.new(event_id: '1', stack_id: '1', stack_name: 'blah', timestamp: Time.now), + OpenStruct.new(event_id: '2', stack_id: '1', stack_name: 'blah', timestamp: Time.now) + ] + } it 'returns stack events' do events = StackMaster::StackEvents::Fetcher.fetch(stack_name, 'us-east-1') diff --git a/spec/stack_master/stack_events/presenter_spec.rb b/spec/stack_master/stack_events/presenter_spec.rb index 0957f936..23c511bf 100644 --- a/spec/stack_master/stack_events/presenter_spec.rb +++ b/spec/stack_master/stack_events/presenter_spec.rb @@ -1,18 +1,22 @@ RSpec.describe StackMaster::StackEvents::Presenter do describe "#print_event" do - let(:time) { Time.new(2001,1,1,2,2,2) } + let(:time) { Time.new(2001, 1, 1, 2, 2, 2) } let(:event) do - double(:event, - timestamp: time, - logical_resource_id: 'MyAwesomeQueue', - resource_type: 'AWS::SQS::Queue', - resource_status: 'CREATE_IN_PROGRESS', - resource_status_reason: 'Resource creation Initiated') + double( + :event, + timestamp: time, + logical_resource_id: 'MyAwesomeQueue', + resource_type: 'AWS::SQS::Queue', + resource_status: 'CREATE_IN_PROGRESS', + resource_status_reason: 'Resource creation Initiated' + ) end subject(:print_event) { described_class.print_event($stdout, event) } it "nicely presents event data" do - expect { print_event }.to output("\e[33m2001-01-01 02:02:02 #{time.strftime('%z')} MyAwesomeQueue AWS::SQS::Queue CREATE_IN_PROGRESS Resource creation Initiated\e[0m\n").to_stdout + expect { print_event }.to output("\e[33m2001-01-01 02:02:02 #{time.strftime('%z')} " \ + "MyAwesomeQueue AWS::SQS::Queue CREATE_IN_PROGRESS " \ + "Resource creation Initiated\e[0m\n").to_stdout end end end diff --git a/spec/stack_master/stack_events/streamer_spec.rb b/spec/stack_master/stack_events/streamer_spec.rb index 59bf16ca..dede48be 100644 --- a/spec/stack_master/stack_events/streamer_spec.rb +++ b/spec/stack_master/stack_events/streamer_spec.rb @@ -1,12 +1,20 @@ RSpec.describe StackMaster::StackEvents::Streamer do - let(:events_first_call) { [ - OpenStruct.new(event_id: '1', resource_status: 'BLAH', timestamp: Time.now), - OpenStruct.new(event_id: '2', resource_status: 'BLAH', timestamp: Time.now), - OpenStruct.new(event_id: '3', resource_status: 'BLAH', timestamp: Time.now), - ] } + let(:events_first_call) { + [ + OpenStruct.new(event_id: '1', resource_status: 'BLAH', timestamp: Time.now), + OpenStruct.new(event_id: '2', resource_status: 'BLAH', timestamp: Time.now), + OpenStruct.new(event_id: '3', resource_status: 'BLAH', timestamp: Time.now), + ] + } let(:events_second_call) { events_first_call + [ - OpenStruct.new(event_id: '4', resource_status: 'UPDATE_COMPLETE', resource_type: 'AWS::CloudFormation::Stack', logical_resource_id: stack_name, timestamp: Time.now) + OpenStruct.new( + event_id: '4', + resource_status: 'UPDATE_COMPLETE', + resource_type: 'AWS::CloudFormation::Stack', + logical_resource_id: stack_name, + timestamp: Time.now + ) ] } let(:stack_name) { 'stack-name' } @@ -14,7 +22,10 @@ let(:now) { Time.now } before do - allow(StackMaster::StackEvents::Fetcher).to receive(:fetch).with(stack_name, region, from: now).and_return(events_first_call, events_second_call) + allow(StackMaster::StackEvents::Fetcher) + .to receive(:fetch) + .with(stack_name, region, from: now) + .and_return(events_first_call, events_second_call) allow(Time).to receive(:now).and_return(now) end @@ -34,14 +45,19 @@ context "the stack is in a failed state" do let(:events_second_call) { events_first_call + [ - OpenStruct.new(event_id: '4', resource_status: 'ROLLBACK_FAILED', resource_type: 'AWS::CloudFormation::Stack', logical_resource_id: stack_name, timestamp: Time.now) + OpenStruct.new( + event_id: '4', + resource_status: 'ROLLBACK_FAILED', + resource_type: 'AWS::CloudFormation::Stack', + logical_resource_id: stack_name, + timestamp: Time.now + ) ] } it 'raises an error on failure' do - expect { - StackMaster::StackEvents::Streamer.stream(stack_name, region, sleep_between_fetches: 0) - }.to raise_error(StackMaster::StackEvents::Streamer::StackFailed) + expect { StackMaster::StackEvents::Streamer.stream(stack_name, region, sleep_between_fetches: 0) } + .to raise_error(StackMaster::StackEvents::Streamer::StackFailed) end end end diff --git a/spec/stack_master/stack_spec.rb b/spec/stack_master/stack_spec.rb index 5a147db4..36abf957 100644 --- a/spec/stack_master/stack_spec.rb +++ b/spec/stack_master/stack_spec.rb @@ -14,8 +14,8 @@ context 'when the stack exists in AWS' do let(:parameters) { [ - {parameter_key: 'param1', parameter_value: 'value1'}, - {parameter_key: 'param2', parameter_value: 'value2'} + { parameter_key: 'param1', parameter_value: 'value1' }, + { parameter_key: 'param2', parameter_value: 'value2' } ] } before do @@ -48,7 +48,7 @@ end it 'parses parameters into a hash' do - expect(stack.parameters).to eq({'param1' => 'value1', 'param2' => 'value2'}) + expect(stack.parameters).to eq({ 'param1' => 'value1', 'param2' => 'value2' }) end it 'sets role_arn' do @@ -88,11 +88,28 @@ end describe '.generate_without_parameters' do - let(:tags) { {'tag1' => 'value1'} } - let(:stack_definition) { StackMaster::StackDefinition.new(region: region, stack_name: stack_name, tags: tags, base_dir: '/base_dir', template: template_file_name, notification_arns: ['test_arn'], role_arn: 'test_service_role_arn', stack_policy_file: 'no_replace_rds.json') } - let(:config) { StackMaster::Config.new({'stacks' => {}}, '/base_dir') } + let(:tags) { { 'tag1' => 'value1' } } + + let(:stack_definition) do + StackMaster::StackDefinition.new( + region: region, + stack_name: stack_name, + tags: tags, + base_dir: '/base_dir', + template: template_file_name, + notification_arns: ['test_arn'], + role_arn: 'test_service_role_arn', + stack_policy_file: 'no_replace_rds.json' + ) + end + + let(:config) { StackMaster::Config.new({ 'stacks' => {} }, '/base_dir') } + subject(:stack) { StackMaster::Stack.generate_without_parameters(stack_definition, config) } - let(:parameter_hash) { {template_parameters: {'DbPassword' => {'secret' => 'db_password'}}, compile_time_parameters: {}} } + + let(:parameter_hash) do + { template_parameters: { 'DbPassword' => { 'secret' => 'db_password' } }, compile_time_parameters: {} } + end let(:resolved_compile_time_parameters) { {} } let(:template_file_name) { 'template.rb' } let(:template_body) { <<~JSON } @@ -116,17 +133,28 @@ let(:stack_policy_body) { '{}' } before do - allow(StackMaster::ParameterLoader).to receive(:load).and_return(parameter_hash) - allow(StackMaster::ParameterResolver).to receive(:resolve).with(config,stack_definition,parameter_hash[:compile_time_parameters]).and_return(resolved_compile_time_parameters) - allow(StackMaster::TemplateCompiler).to receive(:compile).with( - config, - stack_definition.compiler, - stack_definition.template_dir, - stack_definition.template, - resolved_compile_time_parameters, - stack_definition.compiler_options - ).and_return(template_body) - allow(File).to receive(:read).with(stack_definition.stack_policy_file_path).and_return(stack_policy_body) + allow(StackMaster::ParameterLoader) + .to receive(:load) + .and_return(parameter_hash) + allow(StackMaster::ParameterResolver) + .to receive(:resolve) + .with(config, stack_definition, parameter_hash[:compile_time_parameters]) + .and_return(resolved_compile_time_parameters) + allow(StackMaster::TemplateCompiler) + .to receive(:compile) + .with( + config, + stack_definition.compiler, + stack_definition.template_dir, + stack_definition.template, + resolved_compile_time_parameters, + stack_definition.compiler_options + ) + .and_return(template_body) + allow(File) + .to receive(:read) + .with(stack_definition.stack_policy_file_path) + .and_return(stack_policy_body) end it 'has the stack definitions region' do @@ -180,12 +208,16 @@ end describe '.generate' do - let(:tags) { {'tag1' => 'value1'} } + let(:tags) { { 'tag1' => 'value1' } } let(:stack_definition) { StackMaster::StackDefinition.new(region: region, stack_name: stack_name, tags: tags, base_dir: '/base_dir', template: template_file_name, notification_arns: ['test_arn'], role_arn: 'test_service_role_arn', stack_policy_file: 'no_replace_rds.json') } - let(:config) { StackMaster::Config.new({'stacks' => {}}, '/base_dir') } + let(:config) { StackMaster::Config.new({ 'stacks' => {} }, '/base_dir') } subject(:stack) { StackMaster::Stack.generate(stack_definition, config) } - let(:parameter_hash) { {template_parameters: {'DbPassword' => {'secret' => 'db_password'}}, compile_time_parameters: {}} } - let(:resolved_template_parameters) { {'DbPassword' => 'sdfgjkdhlfjkghdflkjghdflkjg', 'InstanceType' => 't2.medium'} } + let(:parameter_hash) { + { template_parameters: { 'DbPassword' => { 'secret' => 'db_password' } }, compile_time_parameters: {} } + } + let(:resolved_template_parameters) { + { 'DbPassword' => 'sdfgjkdhlfjkghdflkjghdflkjg', 'InstanceType' => 't2.medium' } + } let(:resolved_compile_time_parameters) { {} } let(:template_file_name) { 'template.rb' } let(:template_body) { <<~JSON } @@ -209,18 +241,32 @@ let(:stack_policy_body) { '{}' } before do - allow(StackMaster::ParameterLoader).to receive(:load).and_return(parameter_hash) - allow(StackMaster::ParameterResolver).to receive(:resolve).with(config,stack_definition,parameter_hash[:template_parameters]).and_return(resolved_template_parameters) - allow(StackMaster::ParameterResolver).to receive(:resolve).with(config,stack_definition,parameter_hash[:compile_time_parameters]).and_return(resolved_compile_time_parameters) - allow(StackMaster::TemplateCompiler).to receive(:compile).with( - config, - stack_definition.compiler, - stack_definition.template_dir, - stack_definition.template, - resolved_compile_time_parameters, - stack_definition.compiler_options - ).and_return(template_body) - allow(File).to receive(:read).with(stack_definition.stack_policy_file_path).and_return(stack_policy_body) + allow(StackMaster::ParameterLoader) + .to receive(:load) + .and_return(parameter_hash) + allow(StackMaster::ParameterResolver) + .to receive(:resolve) + .with(config, stack_definition, parameter_hash[:template_parameters]) + .and_return(resolved_template_parameters) + allow(StackMaster::ParameterResolver) + .to receive(:resolve) + .with(config, stack_definition, parameter_hash[:compile_time_parameters]) + .and_return(resolved_compile_time_parameters) + allow(StackMaster::TemplateCompiler) + .to receive(:compile) + .with( + config, + stack_definition.compiler, + stack_definition.template_dir, + stack_definition.template, + resolved_compile_time_parameters, + stack_definition.compiler_options + ) + .and_return(template_body) + allow(File) + .to receive(:read) + .with(stack_definition.stack_policy_file_path) + .and_return(stack_policy_body) end it 'has the stack definitions region' do diff --git a/spec/stack_master/template_compiler_spec.rb b/spec/stack_master/template_compiler_spec.rb index 403de7f7..1c321e00 100644 --- a/spec/stack_master/template_compiler_spec.rb +++ b/spec/stack_master/template_compiler_spec.rb @@ -12,8 +12,18 @@ def self.compile(template_dir, template, compile_time_parameters, compile_option context 'when a template compiler is explicitly specified' do it 'uses it' do - expect(StackMaster::TemplateCompilers::SparkleFormation).to receive(:compile).with('/base_dir/templates', 'template', compile_time_parameters, anything) - StackMaster::TemplateCompiler.compile(config, :sparkle_formation, '/base_dir/templates', 'template', compile_time_parameters, compile_time_parameters) + expect(StackMaster::TemplateCompilers::SparkleFormation) + .to receive(:compile) + .with('/base_dir/templates', 'template', compile_time_parameters, anything) + + StackMaster::TemplateCompiler.compile( + config, + :sparkle_formation, + '/base_dir/templates', + 'template', + compile_time_parameters, + compile_time_parameters + ) end end @@ -23,23 +33,40 @@ def self.compile(template_dir, template, compile_time_parameters, compile_option } it 'compiles the template using the relevant template compiler' do - expect(TestTemplateCompiler).to receive(:compile).with(nil, template, compile_time_parameters, anything) - StackMaster::TemplateCompiler.compile(config, nil, nil, template, compile_time_parameters, compile_time_parameters) + expect(TestTemplateCompiler) + .to receive(:compile) + .with(nil, template, compile_time_parameters, anything) + + StackMaster::TemplateCompiler.compile( + config, + nil, + nil, + template, + compile_time_parameters, + compile_time_parameters + ) end it 'passes compile_options to the template compiler' do - opts = {foo: 1, bar: true, baz: "meh"} + opts = { foo: 1, bar: true, baz: "meh" } expect(TestTemplateCompiler).to receive(:compile).with(nil, template, compile_time_parameters, opts) - StackMaster::TemplateCompiler.compile(config, nil, nil, template, compile_time_parameters,opts) + StackMaster::TemplateCompiler.compile(config, nil, nil, template, compile_time_parameters, opts) end context 'when template compilation fails' do before { allow(TestTemplateCompiler).to receive(:compile).and_raise(RuntimeError) } it 'raise TemplateCompilationFailed exception' do - expect{ StackMaster::TemplateCompiler.compile(config, nil, template_dir, template, compile_time_parameters, compile_time_parameters) - }.to raise_error( - StackMaster::TemplateCompiler::TemplateCompilationFailed, /^Failed to compile/) + expect { + StackMaster::TemplateCompiler.compile( + config, + nil, + template_dir, + template, + compile_time_parameters, + compile_time_parameters + ) + }.to raise_error(StackMaster::TemplateCompiler::TemplateCompilationFailed, /^Failed to compile/) end end end diff --git a/spec/stack_master/template_compilers/cfndsl_spec.rb b/spec/stack_master/template_compilers/cfndsl_spec.rb index 94b907bb..fa58f1b9 100644 --- a/spec/stack_master/template_compilers/cfndsl_spec.rb +++ b/spec/stack_master/template_compilers/cfndsl_spec.rb @@ -1,6 +1,5 @@ RSpec.describe StackMaster::TemplateCompilers::Cfndsl do - - let(:compile_time_parameters) { {'InstanceType' => 't2.medium'} } + let(:compile_time_parameters) { { 'InstanceType' => 't2.medium' } } before(:all) { described_class.require_dependencies } let(:template_dir) { 'spec/fixtures/templates/rb/cfndsl/' } @@ -30,13 +29,14 @@ def compile end context 'compiling multiple times' do - let(:compile_time_parameters) { {'InstanceType' => 't2.medium', 'DisableApiTermination' => 'true'} } + let(:compile_time_parameters) { { 'InstanceType' => 't2.medium', 'DisableApiTermination' => 'true' } } let(:template) { 'sample-ctp-repeated.rb' } it 'does not leak compile time params across invocations' do - expect { - compile_time_parameters.delete("DisableApiTermination") - }.to change { JSON.parse(compile)["Resources"]["MyInstance"]["Properties"]["DisableApiTermination"] }.from('true').to('false') + expect { compile_time_parameters.delete("DisableApiTermination") } + .to change { JSON.parse(compile)["Resources"]["MyInstance"]["Properties"]["DisableApiTermination"] } + .from('true') + .to('false') end end end diff --git a/spec/stack_master/template_compilers/json_spec.rb b/spec/stack_master/template_compilers/json_spec.rb index b132dc2d..b0d6997f 100644 --- a/spec/stack_master/template_compilers/json_spec.rb +++ b/spec/stack_master/template_compilers/json_spec.rb @@ -1,5 +1,4 @@ RSpec.describe StackMaster::TemplateCompilers::Json do - let(:compile_time_parameters) { { 'InstanceType' => 't2.medium' } } describe '.compile' do @@ -7,8 +6,10 @@ def compile described_class.compile(stack_definition.template_dir, stack_definition.template, compile_time_parameters) end - let(:stack_definition) { StackMaster::StackDefinition.new(template_dir: File.dirname(template_file_path), - template: File.basename(template_file_path)) } + let(:stack_definition) { + StackMaster::StackDefinition.new(template_dir: File.dirname(template_file_path), + template: File.basename(template_file_path)) + } let(:template_file_path) { '/base_dir/templates/template.json' } context "small json template" do diff --git a/spec/stack_master/template_compilers/sparkle_formation_spec.rb b/spec/stack_master/template_compilers/sparkle_formation_spec.rb index b4c91484..5fa6145a 100644 --- a/spec/stack_master/template_compilers/sparkle_formation_spec.rb +++ b/spec/stack_master/template_compilers/sparkle_formation_spec.rb @@ -28,17 +28,31 @@ def compile end let(:stack_definition) { - instance_double(StackMaster::StackDefinition, + instance_double( + StackMaster::StackDefinition, template: template, - template_dir: template_dir) + template_dir: template_dir + ) } - let(:compile_time_parameters) { {'Ip' => '10.0.0.0', 'Name' => 'Something'} } + let(:compile_time_parameters) { { 'Ip' => '10.0.0.0', 'Name' => 'Something' } } let(:compiler_options) { {} } let(:template) { 'template.rb' } context 'without sparkle packs' do it 'compiles with sparkleformation' do - expect(compile).to eq("{\n \"Description\": \"A test VPC template\",\n \"Resources\": {\n \"Vpc\": {\n \"Type\": \"AWS::EC2::VPC\",\n \"Properties\": {\n \"CidrBlock\": \"10.200.0.0/16\"\n }\n }\n }\n}") + expect(compile).to eq(<<~JSON.chomp) + { + "Description": "A test VPC template", + "Resources": { + "Vpc": { + "Type": "AWS::EC2::VPC", + "Properties": { + "CidrBlock": "10.200.0.0/16" + } + } + } + } + JSON end it 'sets the appropriate sparkle_path' do @@ -49,21 +63,30 @@ def compile context 'compile time parameters validations' do it 'should validate the compile time definitions' do definitions_validator = instance_double(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator) - expect(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator).to receive(:new).with(compile_time_parameter_definitions).and_return(definitions_validator) + expect(StackMaster::SparkleFormation::CompileTime::DefinitionsValidator) + .to receive(:new) + .with(compile_time_parameter_definitions) + .and_return(definitions_validator) expect(definitions_validator).to receive(:validate) compile end it 'should validate the parameters against any compile time definitions' do parameters_validator = instance_double(StackMaster::SparkleFormation::CompileTime::ParametersValidator) - expect(StackMaster::SparkleFormation::CompileTime::ParametersValidator).to receive(:new).with(compile_time_parameter_definitions, compile_time_parameters).and_return(parameters_validator) + expect(StackMaster::SparkleFormation::CompileTime::ParametersValidator) + .to receive(:new) + .with(compile_time_parameter_definitions, compile_time_parameters) + .and_return(parameters_validator) expect(parameters_validator).to receive(:validate) compile end it 'should create the compile state' do state_builder = instance_double(StackMaster::SparkleFormation::CompileTime::StateBuilder) - expect(StackMaster::SparkleFormation::CompileTime::StateBuilder).to receive(:new).with(compile_time_parameter_definitions, compile_time_parameters).and_return(state_builder) + expect(StackMaster::SparkleFormation::CompileTime::StateBuilder) + .to receive(:new) + .with(compile_time_parameter_definitions, compile_time_parameters) + .and_return(state_builder) expect(state_builder).to receive(:build) compile end @@ -71,7 +94,7 @@ def compile end context 'with a custom sparkle_path' do - let(:compiler_options) { {'sparkle_path' => sparkle_pack_dir} } + let(:compiler_options) { { 'sparkle_path' => sparkle_pack_dir } } it 'expands the given path' do compile @@ -81,29 +104,46 @@ def compile context 'with sparkle packs' do let(:compile_time_parameters) { {} } - let(:compiler_options) { {"sparkle_packs" => ["my_sparkle_pack"]} } + let(:compiler_options) { { "sparkle_packs" => ["my_sparkle_pack"] } } before do - lib = File.join(File.dirname(__FILE__), "..", "..", "fixtures", "sparkle_pack_integration", "my_sparkle_pack", "lib") + lib = File.join(File.dirname(__FILE__), "..", "..", "fixtures", "sparkle_pack_integration", "my_sparkle_pack", + "lib") $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) end context 'compiling a sparkle pack dynamic' do let(:template) { 'template_with_dynamic_from_pack' } - let(:compiler_options) { {"sparkle_packs" => ["my_sparkle_pack"], "sparkle_pack_template" => true} } + let(:compiler_options) { { "sparkle_packs" => ["my_sparkle_pack"], "sparkle_pack_template" => true } } it 'pulls the dynamic from the sparkle pack' do - expect(compile).to eq(%Q({\n \"Outputs\": {\n \"Foo\": {\n \"Value\": \"bar\"\n }\n }\n})) + expect(compile).to eq(<<~JSON.chomp) + { + "Outputs": { + "Foo": { + "Value": "bar" + } + } + } + JSON end end context 'compiling a sparkle pack template' do let(:template) { 'template_with_dynamic' } - let(:compiler_options) { {"sparkle_packs" => ["my_sparkle_pack"], "sparkle_pack_template" => true} } + let(:compiler_options) { { "sparkle_packs" => ["my_sparkle_pack"], "sparkle_pack_template" => true } } context 'when template is found' do it 'resolves template location' do - expect(compile).to eq("{\n \"Outputs\": {\n \"Bar\": {\n \"Value\": \"local_dynamic\"\n }\n }\n}") + expect(compile).to eq(<<~JSON.chomp) + { + "Outputs": { + "Bar": { + "Value": "local_dynamic" + } + } + } + JSON end end diff --git a/spec/stack_master/template_compilers/yaml_erb_spec.rb b/spec/stack_master/template_compilers/yaml_erb_spec.rb index afcebedb..952e6d1a 100644 --- a/spec/stack_master/template_compilers/yaml_erb_spec.rb +++ b/spec/stack_master/template_compilers/yaml_erb_spec.rb @@ -49,7 +49,7 @@ VpcId: !Ref Vpc CidrBlock: 10.0.2.0/28 AvailabilityZone: ap-southeast-1 - YAML + YAML end end diff --git a/spec/stack_master/template_compilers/yaml_spec.rb b/spec/stack_master/template_compilers/yaml_spec.rb index e463da38..fd19f4ff 100644 --- a/spec/stack_master/template_compilers/yaml_spec.rb +++ b/spec/stack_master/template_compilers/yaml_spec.rb @@ -1,15 +1,16 @@ RSpec.describe StackMaster::TemplateCompilers::Yaml do describe '.compile' do - - let(:compile_time_parameters) { {'InstanceType' => 't2.medium'} } + let(:compile_time_parameters) { { 'InstanceType' => 't2.medium' } } def compile described_class.compile(stack_definition.template_dir, stack_definition.template, compile_time_parameters) end context 'valid YAML template' do - let(:stack_definition) { StackMaster::StackDefinition.new(template_dir: 'spec/fixtures/templates/yml', - template: 'valid_myapp_vpc.yml') } + let(:stack_definition) { + StackMaster::StackDefinition.new(template_dir: 'spec/fixtures/templates/yml', + template: 'valid_myapp_vpc.yml') + } it 'produces valid YAML' do valid_myapp_vpc_yaml = File.read(stack_definition.template_file_path) diff --git a/spec/stack_master/template_utils_spec.rb b/spec/stack_master/template_utils_spec.rb index 4e86162d..a9611dc3 100644 --- a/spec/stack_master/template_utils_spec.rb +++ b/spec/stack_master/template_utils_spec.rb @@ -17,7 +17,7 @@ context "with a non-json template body" do let(:template_body) { 'AWSTemplateFormatVersion: 2010-09-09' } - it { is_expected.to eq(:yaml) } + it { is_expected.to eq(:yaml) } end end diff --git a/spec/stack_master/test_driver/cloud_formation_spec.rb b/spec/stack_master/test_driver/cloud_formation_spec.rb index 475c120c..c13f4b57 100644 --- a/spec/stack_master/test_driver/cloud_formation_spec.rb +++ b/spec/stack_master/test_driver/cloud_formation_spec.rb @@ -14,7 +14,8 @@ test_cf_driver.add_stack_event(stack_name: 'stack-1', resource_status: "UPDATE_COMPLETE") test_cf_driver.add_stack_event(stack_name: 'stack-1', resource_status: "UPDATE_COMPLETE") test_cf_driver.add_stack_event(stack_name: 'stack-2') - expect(test_cf_driver.describe_stack_events(stack_name: 'stack-1').stack_events.map(&:stack_name)).to eq ['stack-1', 'stack-1'] + expect(test_cf_driver.describe_stack_events(stack_name: 'stack-1').stack_events.map(&:stack_name)) + .to eq(['stack-1', 'stack-1']) end it 'sets and gets templates' do @@ -35,7 +36,7 @@ stack_name: 'stack-1', change_set_name: 'change-set-1', template_body: '{}', - parameters: [{ paramater_key: 'param_1', parameter_value: 'value_1'}] + parameters: [{ paramater_key: 'param_1', parameter_value: 'value_1' }] ).id change_set = test_cf_driver.describe_change_set(change_set_name: change_set_id) expect(change_set.change_set_id).to eq change_set_id @@ -46,8 +47,16 @@ end it 'creates stacks using change sets and describes stacks' do - change_set1 = test_cf_driver.create_change_set(change_set_name: 'change-set-1', stack_name: 'stack-1', change_set_type: 'CREATE') - change_set2 = test_cf_driver.create_change_set(change_set_name: 'change-set-2', stack_name: 'stack-2', change_set_type: 'CREATE') + change_set1 = test_cf_driver.create_change_set( + change_set_name: 'change-set-1', + stack_name: 'stack-1', + change_set_type: 'CREATE' + ) + change_set2 = test_cf_driver.create_change_set( + change_set_name: 'change-set-2', + stack_name: 'stack-2', + change_set_type: 'CREATE' + ) test_cf_driver.execute_change_set(change_set_name: change_set1.id) test_cf_driver.execute_change_set(change_set_name: change_set2.id) expect(test_cf_driver.describe_stacks.stacks.map(&:stack_name)).to eq(['stack-1', 'stack-2']) diff --git a/spec/stack_master/utils_spec.rb b/spec/stack_master/utils_spec.rb index 771afdf1..3076c34e 100644 --- a/spec/stack_master/utils_spec.rb +++ b/spec/stack_master/utils_spec.rb @@ -1,10 +1,10 @@ RSpec.describe StackMaster::Utils do describe ".hash_to_aws_tags" do - let(:tags) { {'environment' => 'production'} } + let(:tags) { { 'environment' => 'production' } } subject(:aws_tags) { StackMaster::Utils.hash_to_aws_tags(tags) } it "converts the tags attribute to aws format" do - expect(aws_tags).to eq([{key: 'environment', value: 'production'}]) + expect(aws_tags).to eq([{ key: 'environment', value: 'production' }]) end context "tags is nil" do @@ -21,10 +21,12 @@ subject(:aws_params) { StackMaster::Utils.hash_to_aws_parameters(params) } it "converts to aws parameters" do - expect(aws_params).to eq([ - { parameter_key: 'param1', parameter_value: 'value1' }, - { parameter_key: 'param2', parameter_value: 'value2' } - ]) + expect(aws_params).to eq( + [ + { parameter_key: 'param1', parameter_value: 'value1' }, + { parameter_key: 'param2', parameter_value: 'value2' } + ] + ) end end end diff --git a/spec/stack_master/validator_spec.rb b/spec/stack_master/validator_spec.rb index 2d366777..31351abd 100644 --- a/spec/stack_master/validator_spec.rb +++ b/spec/stack_master/validator_spec.rb @@ -1,7 +1,6 @@ RSpec.describe StackMaster::Validator do - subject(:validator) { described_class.new(stack_definition, config, options) } - let(:config) { StackMaster::Config.new({'stacks' => {}}, '/base_dir') } + let(:config) { StackMaster::Config.new({ 'stacks' => {} }, '/base_dir') } let(:options) { Commander::Command::Options.new } let(:stack_name) { 'myapp_vpc' } let(:template_file) { 'myapp_vpc.json' } @@ -10,13 +9,16 @@ region: 'us-east-1', stack_name: stack_name, template: template_file, - tags: {'environment' => 'production'}, + tags: { 'environment' => 'production' }, base_dir: File.expand_path('spec/fixtures'), ) end let(:cf) { spy(Aws::CloudFormation::Client, validate_template: nil) } - let(:parameter_hash) { {template_parameters: {}, compile_time_parameters: {'DbPassword' => {'secret' => 'db_password'}}} } - let(:resolved_parameters) { {'DbPassword' => 'sdfgjkdhlfjkghdflkjghdflkjg', 'InstanceType' => 't2.medium'} } + let(:parameter_hash) do + { template_parameters: {}, compile_time_parameters: { 'DbPassword' => { 'secret' => 'db_password' } } } + end + let(:resolved_parameters) { { 'DbPassword' => 'sdfgjkdhlfjkghdflkjghdflkjg', 'InstanceType' => 't2.medium' } } + before do allow(Aws::CloudFormation::Client).to receive(:new).and_return cf allow(StackMaster::ParameterLoader).to receive(:load).and_return(parameter_hash) @@ -32,7 +34,9 @@ context "invalid template body" do before do - allow(cf).to receive(:validate_template).and_raise(Aws::CloudFormation::Errors::ValidationError.new('a', 'Problem')) + allow(cf) + .to receive(:validate_template) + .and_raise(Aws::CloudFormation::Errors::ValidationError.new('a', 'Problem')) end it "informs the user of their stupdity" do @@ -68,5 +72,4 @@ end end end - end diff --git a/stack_master.gemspec b/stack_master.gemspec index 4e9f5265..22ae8e92 100644 --- a/stack_master.gemspec +++ b/stack_master.gemspec @@ -1,4 +1,5 @@ # coding: utf-8 + lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) require 'stack_master/version' @@ -9,15 +10,16 @@ Gem::Specification.new do |spec| spec.version = StackMaster::VERSION spec.authors = ["Steve Hodgkiss", "Glen Stampoultzis"] spec.email = ["steve@hodgkiss.me", "gstamp@gmail.com"] - spec.summary = %q{StackMaster is a sure-footed way of creating, updating and keeping track of Amazon (AWS) CloudFormation stacks.} + spec.summary = 'StackMaster is a sure-footed way of creating, updating and keeping track ' \ + 'of Amazon (AWS) CloudFormation stacks.' spec.description = %q{} spec.homepage = "https://opensource.envato.com/projects/stack_master.html" spec.license = "MIT" spec.metadata = { - "bug_tracker_uri" => "https://github.com/envato/stack_master/issues", - "changelog_uri" => "https://github.com/envato/stack_master/blob/master/CHANGELOG.md", + "bug_tracker_uri" => "https://github.com/envato/stack_master/issues", + "changelog_uri" => "https://github.com/envato/stack_master/blob/master/CHANGELOG.md", "documentation_uri" => "https://www.rubydoc.info/gems/stack_master/#{spec.version}", - "source_code_uri" => "https://github.com/envato/stack_master/tree/v#{spec.version}", + "source_code_uri" => "https://github.com/envato/stack_master/tree/v#{spec.version}", } spec.files = Dir.glob("{bin,lib,stacktemplates}/**/*") + %w(README.md LICENSE.txt)