From 408be68702f2b09b568ecb6ce0fecde841396b97 Mon Sep 17 00:00:00 2001 From: ThomasBuchinger Date: Sun, 27 Jan 2019 23:36:33 +0100 Subject: [PATCH] Finalize Configuration and CLI (#37) * Add missing CLI flags and ENV variables to configuration * Restructure CLI layout. Add 'branch' and 'domain' sub commands * Refactor: Separate Config sources from Settings-Value MiqFlow::Config now does the config processing and presents the update_* methods to the rest of the program MiqFlow::Settings implements the update_* methods * FIX wrong boolean for clear_tmp * Add support for /etc/miqflow.yaml * Remove support for configuration files in the current working directory * Add support for configurable branch naming conventions * Removes unnecessary restriction for branch names * Replace invalid charachters in MIQ domain names * Shorten domain prefix to 'feat' (prev 'feature') * Refactor Travis build --- .rubocop.yml | 4 ++ .travis.yml | 15 ++++--- config.yaml | 15 ++++++- lib/miq_flow.rb | 5 ++- lib/miq_flow/cli.rb | 2 +- lib/miq_flow/cli/branch.rb | 31 +++++++++++++++ lib/miq_flow/cli/cli.rb | 68 ------------------------------- lib/miq_flow/cli/domain.rb | 19 +++++++++ lib/miq_flow/cli/list.rb | 28 ------------- lib/miq_flow/cli/main.rb | 73 ++++++++++++++++++++++++++++++++++ lib/miq_flow/domain.rb | 2 +- lib/miq_flow/feature.rb | 9 +++-- lib/miq_flow/miqflow.rb | 3 +- lib/miq_flow/mixin_config.rb | 64 +++++++++++++++++++++++++++++ lib/miq_flow/mixin_git.rb | 2 +- lib/miq_flow/mixin_miq.rb | 35 ++++++++++++++++ lib/miq_flow/mixin_settings.rb | 72 +++++++++++---------------------- script/prepare_manageiq.sh | 3 +- script/verify_import.sh | 3 +- spec/cli_spec.rb | 42 +++++++++---------- spec/miq_utils_spec.rb | 33 +++++++++++++++ 21 files changed, 340 insertions(+), 188 deletions(-) create mode 100755 lib/miq_flow/cli/branch.rb delete mode 100755 lib/miq_flow/cli/cli.rb create mode 100755 lib/miq_flow/cli/domain.rb delete mode 100755 lib/miq_flow/cli/list.rb create mode 100755 lib/miq_flow/cli/main.rb create mode 100644 lib/miq_flow/mixin_config.rb create mode 100644 spec/miq_utils_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 4a99765..3f04068 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,6 +12,10 @@ Metrics/MethodLength: Max: 50 Metrics/AbcSize: Max: 20 + Exclude: + # mixin_config tends to overshoot, but is + # still easily readable + - lib/miq_flow/mixin_config.rb Layout/SpaceBeforeBlockBraces: EnforcedStyle: no_space diff --git a/.travis.yml b/.travis.yml index b79649d..6e5cf2e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,15 +15,14 @@ matrix: env: TAG=latest - name: "Hammer + Integration" rvm: 2.4 - env: TAG=latest-hammer SUITE=integration - -before_install: - - script/prepare_manageiq.sh - - ruby -ryaml -e "c={'log_level'=>'debug', 'git'=>{'url'=>'https://github.com/ThomasBuchinger/automate-example'}}; puts c.to_yaml" > config.yaml + env: TAG=latest-hammer GIT_URL=https://github.com/ThomasBuchinger/automate-example + stage: integration + script: + - script/prepare_manageiq.sh + - rake install:local + - miq-flow deploy feature-1-f1 --provider docker --git-index 2 + - ./script/verify_import.sh script: - bundle check # ManageIQ Container/Appliance needs to satisfy all dependencies - - rake install:local - - miq-flow deploy feature-1-f1 --provider docker - - ./script/verify_import.sh - bundle install --with development - bundle exec rake travis diff --git a/config.yaml b/config.yaml index 6495b75..2dd882f 100644 --- a/config.yaml +++ b/config.yaml @@ -1,7 +1,8 @@ --- # Set logging level +# If set to no_log, no log output will be generated # Default: info -# Possible values: debug, info, warn, error, fatal +# Possible values: debug, info, warn, error, fatal, no_log # log_level: info # git: @@ -19,7 +20,17 @@ # Specify credentials for the repository. # NOTE: only HTTP Authenication is supported # user: someone - # password: + # pashsword: + + # Branch naming scheme + # This configures the naming scheme for your git branches (if you use one) + # and how MiqFlow derives a name for the domains imported from that branch. + # The default configuration matches: TYPE-NAME-optional-description + # + # characters used to separate part of yu naming convention + # separators: [ '-', '/' ] + # index of the NAME part in your naming convention (starts with 0) + # index: 1 # miq: # url: https://localhost/api diff --git a/lib/miq_flow.rb b/lib/miq_flow.rb index 2ff768c..9176429 100644 --- a/lib/miq_flow.rb +++ b/lib/miq_flow.rb @@ -18,14 +18,15 @@ require 'miq_flow/mixin_git' require 'miq_flow/mixin_api' require 'miq_flow/mixin_settings' +require 'miq_flow/mixin_config' require 'miq_flow/manageiq' require 'miq_flow/domain' require 'miq_flow/feature' require 'miq_flow/miqflow' -require 'miq_flow/cli/cli' +require 'miq_flow/cli' require 'miq_flow/version' $settings = {} $settings[:miq] = {} $settings[:git] = {} -MiqFlow::Settings.set_defaults() +MiqFlow::Config.set_defaults() diff --git a/lib/miq_flow/cli.rb b/lib/miq_flow/cli.rb index 2449cc0..2a8d46d 100644 --- a/lib/miq_flow/cli.rb +++ b/lib/miq_flow/cli.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -require_relative 'cli/cli.rb' +require_relative 'cli/main.rb' diff --git a/lib/miq_flow/cli/branch.rb b/lib/miq_flow/cli/branch.rb new file mode 100755 index 0000000..8700359 --- /dev/null +++ b/lib/miq_flow/cli/branch.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require 'thor' + +module MiqFlow + module Cli + # Implements list subcommand + class BranchCli < Thor + include MiqFlow::Cli + + desc 'list', 'List avaliable Feature Branches' + def list + cli_setup(options, %i[git]) + branches = MiqFlow::GitMethods.get_remote_branches() + text = branches.map{ |b| MiqFlow::Feature.new(b.name, {}).show_summary() } + puts text + MiqFlow.tear_down() + end + + desc 'inspect BRANCH', 'Show detailed information about this Feature-Branch' + option :short, type: :boolean, default: false, desc: 'Same as list' + def inspect(name) + cli_setup(options, %i[git]) + feature = MiqFlow::Feature.new(name, {}) + text = options[:short] ? feature.show_summary() : feature.show_details() + puts text + MiqFlow.tear_down() + end + end + end +end diff --git a/lib/miq_flow/cli/cli.rb b/lib/miq_flow/cli/cli.rb deleted file mode 100755 index 270d99a..0000000 --- a/lib/miq_flow/cli/cli.rb +++ /dev/null @@ -1,68 +0,0 @@ -# frozen_string_literal: true - -require 'thor' -require_relative 'list.rb' - -module MiqFlow - # Implements common CLI methods - module Cli - def cli_setup(options={}, mode=[]) - MiqFlow::Settings.search_config_files() - MiqFlow::Settings.process_environment_variables() - MiqFlow::Settings.process_config_file(options['config']) - MiqFlow::Settings.update_log_level(:debug) if options['verbose'] == true - MiqFlow::Settings.update_log_level(:warn) if options['quiet'] == true - MiqFlow::Settings.update_clear_tmp(options['cleanup']) - MiqFlow::Settings.update_workdir(options['workdir']) - - MiqFlow.validate(mode) - MiqFlow.init() - MiqFlow.prepare_repo() - end - - # Implements CLI - class MainCli < Thor - include MiqFlow::Cli - - def self.exit_on_failure? - true - end - - class_option :verbose, type: :boolean, desc: 'Turn on verbose logging' - class_option :quiet, type: :boolean, desc: 'Only show errors and warnings' - class_option :cleanup, type: :boolean, desc: 'Clean up the working dir before exiting' - class_option :workdir, type: :string, desc: 'Override the working directory' - class_option :config, type: :string, alias: '-c', desc: 'Specify config file to load' - - desc 'list branches|domains', 'Show summary information' - subcommand 'list', MiqFlow::Cli::ListCli - - desc 'inspect BRANCH', 'Show detailed information about this Feature-Branch' - option :short, type: :boolean, default: false, desc: 'Same as list' - def inspect(name) - cli_setup(options, %i[git]) - feature = MiqFlow::Feature.new(name, {}) - text = options[:short] ? feature.show_summary() : feature.show_details() - puts text - MiqFlow.tear_down() - end - - desc 'deploy BRANCH', 'Deploy a Feature Branch' - option :name, desc: 'specify domain identifier (default: 3rd segment of NAME, separated by \'-\')' - option :priority, type: :numeric, desc: 'Not-yet-implemented' - option :provider, desc: 'How to talk to ManageIQ (default: noop)' - def deploy(branch) - cli_setup(options, %i[git miq]) - miq_domain = options[:name] || branch.split(/-/)[2] || branch - provider = options.fetch(:provider, 'default') - prio = options[:miq_priority] - - opts = { feature_name: miq_domain, provider: provider } - opts[:miq_priotiry] = prio - feature = MiqFlow::Feature.new(branch, opts) - feature.deploy() - MiqFlow.tear_down() - end - end - end -end diff --git a/lib/miq_flow/cli/domain.rb b/lib/miq_flow/cli/domain.rb new file mode 100755 index 0000000..9101fc7 --- /dev/null +++ b/lib/miq_flow/cli/domain.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +require 'thor' + +module MiqFlow + module Cli + # Implements list subcommand + class DomainCli < Thor + include MiqFlow::Cli + + desc 'list', 'List existing Automate Domains in ManageIQ' + def list + cli_setup(options, %i[api]) + api = MiqFlow::ManageIQ.new + puts api.list_domains + end + end + end +end diff --git a/lib/miq_flow/cli/list.rb b/lib/miq_flow/cli/list.rb deleted file mode 100755 index 72abdc6..0000000 --- a/lib/miq_flow/cli/list.rb +++ /dev/null @@ -1,28 +0,0 @@ -# frozen_string_literal: true - -require 'thor' - -module MiqFlow - module Cli - # Implements list subcommand - class ListCli < Thor - include MiqFlow::Cli - - desc 'branches', 'List avaliable Feature Branches' - def branches - cli_setup(options, %i[git]) - branches = MiqFlow::GitMethods.get_remote_branches() - text = branches.map{ |b| MiqFlow::Feature.new(b.name, {}).show_summary() } - puts text - MiqFlow.tear_down() - end - - desc 'domains', 'List existing Automate Domains in ManageIQ' - def domains - cli_setup(options, %i[api]) - api = MiqFlow::ManageIQ.new - puts api.list_domains - end - end - end -end diff --git a/lib/miq_flow/cli/main.rb b/lib/miq_flow/cli/main.rb new file mode 100755 index 0000000..ea53df8 --- /dev/null +++ b/lib/miq_flow/cli/main.rb @@ -0,0 +1,73 @@ +# frozen_string_literal: true + +require 'thor' +require_relative 'branch.rb' +require_relative 'domain.rb' + +module MiqFlow + # Implements common CLI methods + module Cli + def cli_setup(options={}, mode=[]) + MiqFlow::Config.process_cli_flags(options) # Set log level first + MiqFlow::Config.search_config_files() + MiqFlow::Config.process_environment_variables() + MiqFlow::Config.process_config_file(options['config']) + MiqFlow::Config.process_cli_flags(options) # And again for precedence + + MiqFlow.validate(mode) + MiqFlow.init() + MiqFlow.prepare_repo() + end + + # Implements CLI + class MainCli < Thor + include MiqFlow::Cli + + def self.exit_on_failure? + true + end + + class_option :verbose, type: :boolean, default: false, desc: 'Turn on verbose logging' + class_option :quiet, type: :boolean, default: false, desc: 'Only show errors and warnings' + class_option :silent, type: :boolean, default: false, desc: 'Do not output anything' + class_option :cleanup, type: :boolean, desc: 'Clean up the working dir before exiting' + class_option :workdir, type: :string, desc: 'Override the working directory' + class_option :config, type: :string, alias: '-c', desc: 'Specify config file to load' + + class_option :git_url, type: :string, desc: 'Git clone URL for remote repositories' + class_option :git_path, type: :string, desc: 'path to a local git repositories' + class_option :git_user, type: :string, desc: 'Username for remote repositories' + class_option :git_password, type: :string, desc: 'Password/token for remote repositories' + class_option :git_separator, type: :string, desc: 'List of characters separating part of your ' \ + 'branch naming convention' + class_option :git_index, type: :numeric, desc: 'Index the NAME par of your branch naming convenion' + + class_option :miq_url, type: :string, desc: 'ManageIQ API URL. (e.g. https://localhost/api)' + class_option :miq_user, type: :string, desc: 'ManageIQ API User. (default: admin)' + class_option :miq_password, type: :string, desc: 'Passwork/login-token for the ManageIQ API User' + + desc 'branch', 'Branch commands' + subcommand 'branch', MiqFlow::Cli::BranchCli + + desc 'domain', 'Domain commands' + subcommand 'domain', MiqFlow::Cli::DomainCli + + desc 'deploy BRANCH', 'Deploy a Feature Branch' + option :name, desc: 'specify domain identifier (default: 3rd segment of NAME, separated by \'-\')' + option :priority, type: :numeric, desc: 'Not-yet-implemented' + option :provider, desc: 'How to talk to ManageIQ (default: noop)' + def deploy(branch) + cli_setup(options, %i[git miq]) + miq_domain = options[:name] + provider = options.fetch(:provider, 'default') + prio = options[:miq_priority] + + opts = { feature_name: miq_domain, provider: provider } + opts[:miq_priotiry] = prio + feature = MiqFlow::Feature.new(branch, opts) + feature.deploy() + MiqFlow.tear_down() + end + end + end +end diff --git a/lib/miq_flow/domain.rb b/lib/miq_flow/domain.rb index 13b15cd..bfb9172 100644 --- a/lib/miq_flow/domain.rb +++ b/lib/miq_flow/domain.rb @@ -50,7 +50,7 @@ def self.create_from_file(dom) opts[:provider_name] = dom[:provider] opts[:branch_name] = dom[:branch_name] - new_name = "feature_#{dom[:feature_name]}_#{opts[:export_name]}" + new_name = "feat_#{dom[:feature_name]}_#{opts[:export_name]}" opts.reject!{ |_, value| value.nil? } self.new(new_name, opts) end diff --git a/lib/miq_flow/feature.rb b/lib/miq_flow/feature.rb index 4d734a1..b600eb2 100644 --- a/lib/miq_flow/feature.rb +++ b/lib/miq_flow/feature.rb @@ -21,9 +21,10 @@ class Feature # @option opts [String] :base('master') # @option opts [Array] :prefix(feature, fix) def _set_defaults(opts={}) - @remote_name = opts.fetch(:remote_name, 'origin') - @base = opts.fetch(:base, 'master') - @prefixes = opts.fetch(:prefix, %w[feature fix]) + @remote_name = opts.fetch(:remote_name, 'origin') + @base = opts.fetch(:base, 'master') + # unused + @prefixes = opts.fetch(:prefix, ['']) end # Represents a feature-branch @@ -32,7 +33,7 @@ def _set_defaults(opts={}) # @option opts @see _set_defaults def initialize(branch_name, opts={}) _set_defaults(opts) - @name = opts.fetch(:feature_name, branch_name.split(/-/)[2]) || File.basename(branch_name) + @name = opts.fetch(:feature_name, nil) || name_from_branch(branch_name) $logger.debug("Creating Feature: branch=#{branch_name} domain=#{@name}") @git_repo = opts.fetch(:git_repo, nil) || $git_repo diff --git a/lib/miq_flow/miqflow.rb b/lib/miq_flow/miqflow.rb index 380f996..6ecfa24 100644 --- a/lib/miq_flow/miqflow.rb +++ b/lib/miq_flow/miqflow.rb @@ -3,6 +3,7 @@ # Global Methods module MiqFlow include MiqFlow::Settings + include MiqFlow::Config include MiqFlow::GitMethods def self.init @@ -23,7 +24,7 @@ def self.prepare_repo end def self.tear_down - clean_tmp_dir() unless $settings[:clear_tmp] + clean_tmp_dir() if $settings[:clear_tmp] end def self.clean_tmp_dir diff --git a/lib/miq_flow/mixin_config.rb b/lib/miq_flow/mixin_config.rb new file mode 100644 index 0000000..25419da --- /dev/null +++ b/lib/miq_flow/mixin_config.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module MiqFlow + # This mixin handles processing of different + # configuration sources (env, file, cli) + module Config + extend Settings + + def self.search_config_files + $settings[:searchpath].each do |file| + process_config_file(file) + end + end + + def self.process_environment_variables + # Git params + update_git(ENV['GIT_URL'], ENV['GIT_PATH'], ENV['GIT_USER'], ENV['GIT_PASSWORD']) + + # MIQ params + update_miq_api(ENV['MIQ_URL'], ENV['MIQ_USER'], ENV['MIQ_PASSWORD']) + + # Misc + update_log_level_with_flags(verbose: ENV['verbose'], quiet: ENV['quiet'], silent: ENV['silent']) + update_clear_tmp(ENV['CLEAR_TMP']) + update_workdir(ENV['WORKDIR']) + update_naming(ENV.fetch('git_separator', '').split(//), ENV['git_index']) + end + + def self.process_cli_flags(options={}) + # Git params + update_git(options['git_url'], options['git_path'], options['git_user'], options['git_password']) + + # MIQ params + update_miq_api(options['miq_url'], options['miq_user'], options['miq_password']) + + # Misc + update_log_level_with_flags(verbose: options['verbose'], quiet: options['quiet'], silent: options['silent']) + update_clear_tmp(options['cleanup']) + update_workdir(options['workdir']) + update_naming(options.fetch('git_separator', '').split(//), options['git_index']) + end + + def self.process_config_file(path) + return unless path.kind_of?(String) && File.file?(path) + + $logger.info("Processing config file: #{path}") + conf = YAML.load_file(path) || {} + git_conf = conf['git'] || {} + miq_conf = conf['miq'] || {} + + # Git params + update_git(git_conf['url'], git_conf['path'], git_conf['user'], git_conf['password']) + + # MIQ params + update_miq_api(miq_conf['url'], miq_conf['user'], miq_conf['password']) + + # Misc + update_log_level(conf['log_level']) + update_clear_tmp(conf['clear_tmp']) + update_workdir(conf['workdir']) + update_naming(git_conf['seperator'], git_conf['index']) + end + end +end diff --git a/lib/miq_flow/mixin_git.rb b/lib/miq_flow/mixin_git.rb index acbac83..65855da 100644 --- a/lib/miq_flow/mixin_git.rb +++ b/lib/miq_flow/mixin_git.rb @@ -108,7 +108,7 @@ def get_path_by_commits(base_commit, head_commit) # @param [String] git remote name used to construct branch name. default: origin # @return [Rugged::Branch] all remote pranches starting with prefix def self.get_remote_branches(prefixes=nil, remote=nil) - prefixes = prefixes || @prefix || %w[feature fix master] + prefixes = prefixes || @prefix || [''] remote_name = remote || @remote || 'origin' repo = @git_repo || $git_repo repo.branches.each(:remote).select do |remote_branch| diff --git a/lib/miq_flow/mixin_miq.rb b/lib/miq_flow/mixin_miq.rb index 3446518..f771b49 100644 --- a/lib/miq_flow/mixin_miq.rb +++ b/lib/miq_flow/mixin_miq.rb @@ -7,6 +7,7 @@ module MiqMethods # ManageIQ related Methods, that are not plugable module MiqUtils DOMAIN_FILE_NAME = '__domain__.yaml' + INVALID_CHARS = /[^A-Za-z0-9_\-\.$]/.freeze # Find and read Automate domains # Search PATH for __domain__.yaml files, indicating a ManageIQ Automate Domain @@ -25,6 +26,40 @@ def find_domain_files(path) h end end + + def split_branch_name(name, separator) + current_index = 0 + sub_str = [] + loop do + index = separator.map{ |s| name.index(s, current_index) }.compact.min + length = (index || name.length) - current_index + sub_str << name.slice(current_index, length) + break if index.nil? + + current_index = index + 1 + end + sub_str + end + + def normalize_domain_name(name) + name.gsub(INVALID_CHARS, '_') + end + + def name_from_branch(name, index: nil, separator: nil) + # branch_map = { + # 'master': 'prod', + # 'develop': 'dev' + # } + # return branch_map[name] if branch_map.key?(name) + separator ||= $settings[:naming_separator] + index ||= $settings[:naming_index] + name = name.gsub("#{@remote_name}/", '') unless @remote_name.nil? + + domain = split_branch_name(name, separator).fetch(index, nil) + return normalize_domain_name(domain) unless domain.nil? || domain.empty? + + normalize_domain_name(name) + end end end end diff --git a/lib/miq_flow/mixin_settings.rb b/lib/miq_flow/mixin_settings.rb index ff46853..1b09a7d 100644 --- a/lib/miq_flow/mixin_settings.rb +++ b/lib/miq_flow/mixin_settings.rb @@ -6,66 +6,37 @@ module MiqFlow # reasonable value is provided module Settings SEARCHPATH = [ - 'config.yml', - 'config.yaml', - 'miqflow.yml', - 'miqflow.yaml', + '/etc/miqflow.yml', + '/etc/miqflow.yaml', File.expand_path('~/.miqflow.yml'), File.expand_path('~/.miqflow.yaml'), File.expand_path('~/.miqflow/config.yml'), File.expand_path('~/.miqflow/config.yaml') ].freeze - def self.set_defaults + def set_defaults update_searchpath(SEARCHPATH.dup, replace: true) update_log_level(:info) update_clear_tmp('yes') update_workdir('auto') update_miq_api(nil, 'admin', nil) + update_naming(['-', '/'], 1) end - def self.search_config_files - $settings[:searchpath].each do |file| - MiqFlow::Settings.process_config_file(file) - end - end - - def self.process_environment_variables - # Git params - update_git(ENV['GIT_URL'], ENV['GIT_PATH'], ENV['GIT_USER'], ENV['GIT_PASSWORD']) - - # MIQ params - update_miq_api(ENV['MIQ_URL'], ENV['MIQ_USER'], ENV['MIQ_PASSWORD']) - - # Misc - update_log_level(:debug) if truthy(ENV.fetch('VERBOSE', 'no')) - update_log_level(:warn) if truthy(ENV.fetch('QUIET', 'no')) - update_clear_tmp(ENV['CLEAR_TMP']) - end - - def self.process_config_file(path) # rubocop:disable Metrics/AbcSize - return unless path.kind_of?(String) && File.file?(path) - - $logger.info("Processing config file: #{path}") - conf = YAML.load_file(path) || {} - git_conf = conf['git'] || {} - miq_conf = conf['miq'] || {} - - update_log_level(conf['log_level']) - update_clear_tmp(conf['clear_tmp']) - update_git(git_conf['url'], git_conf['path'], git_conf['user'], git_conf['password']) - update_miq_api(miq_conf['url'], miq_conf['user'], miq_conf['password']) - update_workdir(conf['workdir']) - end - - def self.update_searchpath(path=[], replace: false) + def update_searchpath(path=[], replace: false) return $settings[:searchpath] = path if replace $settings[:searchpath] = path.concat($settings[:searchpath]) end - def self.update_log_level(level) + def update_log_level_with_flags(verbose: 'no', quiet: 'no', silent: 'no') + update_log_level(:debug) if truthy(verbose) + update_log_level(:warn) if truthy(quiet) + update_log_level(:no_log) if truthy(silent) + end + + def update_log_level(level) return if level.nil? log_level = { @@ -74,7 +45,7 @@ def self.update_log_level(level) warn: Logger::WARN, error: Logger::ERROR, fatal: Logger::FATAL, - unknown: Logger::UNKNOWN + no_log: Logger::UNKNOWN } return unless log_level.key?(level.to_sym) @@ -86,20 +57,25 @@ def self.update_log_level(level) $settings[:log_level] = level end - def self.update_clear_tmp(clear_flag) + def update_clear_tmp(clear_flag) return unless truthy(clear_flag) || falsey(clear_flag) $settings[:clear_tmp] = truthy(clear_flag) end - def self.update_git(url, path, user, password) + def update_git(url, path, user, password) $settings[:git][:url] = url unless url.nil? $settings[:git][:path] = path unless path.nil? $settings[:git][:user] = user unless user.nil? $settings[:git][:password] = password unless password.nil? end - def self.update_workdir(dir) + def update_naming(separators, index) + $settings[:naming_separator] = separators unless separators.nil? || separators.empty? + $settings[:naming_index] = index.to_i unless index.nil? || !index.respond_to?(:to_i) + end + + def update_workdir(dir) return if dir.nil? return if dir != 'auto' && !File.directory?(dir) @@ -107,18 +83,18 @@ def self.update_workdir(dir) $settings[:workdir] = dir end - def self.update_miq_api(url, user, password) + def update_miq_api(url, user, password) $settings[:miq][:url] = url unless url.nil? $settings[:miq][:user] = user unless user.nil? $settings[:miq][:password] = password unless password.nil? end - def self.truthy(value) + def truthy(value) true_values = %w[true TRUE True yes YES Yes t T y Y 1] true_values.include?(value.to_s) end - def self.falsey(value) + def falsey(value) false_values = %w[false FALSE False no NO No f F n N 0] false_values.include?(value.to_s) end diff --git a/script/prepare_manageiq.sh b/script/prepare_manageiq.sh index 5f83b7f..1b5f703 100755 --- a/script/prepare_manageiq.sh +++ b/script/prepare_manageiq.sh @@ -1,8 +1,7 @@ #!/bin/bash CONTAINER_NAME=${CONTAINER_NAME-manageiq} -TAG=${TAG-hammer-1-rc1} +TAG=${TAG-latest-hammer} SUITE=${SUITE-default} -if [[ $SUITE != "integration" ]]; then exit 0; fi docker rm -f $CONTAINER_NAME docker pull manageiq/manageiq:$TAG diff --git a/script/verify_import.sh b/script/verify_import.sh index 1db6f9b..3f4ebda 100755 --- a/script/verify_import.sh +++ b/script/verify_import.sh @@ -1,7 +1,6 @@ #!/bin/bash -DOMAIN=${DOMAIN-feature_f1_buc} +DOMAIN=${DOMAIN-feat_f1_buc} SUITE=${SUITE-default} -if [[ $SUITE != "integration" ]]; then exit 0; fi RESPONSE=$(curl -k --user admin:smartvm "https://localhost:8443/api/automate/${DOMAIN}?depth=-1&attributes=klass,domain_fnname") diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 73b43a2..f1fc295 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -10,12 +10,13 @@ before(:each) do $settings = { git: {}, miq: {} } - MiqFlow::Settings.set_defaults() - MiqFlow::Settings.update_searchpath([], replace: true) - MiqFlow::Settings.update_log_level(:unknown) + MiqFlow::Config.set_defaults() + MiqFlow::Config.update_searchpath([], replace: true) + MiqFlow::Config.update_log_level(:no_log) + MiqFlow::Config.update_naming(nil, 2) - MiqFlow::Settings.update_git(git_url, nil, nil, nil) - MiqFlow::Settings.update_miq_api(miq_url, 'admin', 'smartvm') + MiqFlow::Config.update_git(git_url, nil, nil, nil) + MiqFlow::Config.update_miq_api(miq_url, 'admin', 'smartvm') end context 'General handling' do @@ -27,20 +28,22 @@ end it 'invalid git configuraion: exits with 3' do $settings[:git] = {} - expect{ subject.invoke(:list, ['branches']) }.to raise_error(MiqFlow::ConfigurationError) + expect{ subject.invoke(:branch, ['list']) }.to raise_error(MiqFlow::ConfigurationError) end it 'invalid api configuration: exiths with 3' do $settings[:miq] = {} - expect{ subject.invoke(:list, ['domains']) }.to raise_error(MiqFlow::ConfigurationError) + expect{ subject.invoke(:domain, ['list']) }.to raise_error(MiqFlow::ConfigurationError) end end context 'Basic Commands', git: true do - it 'list git' do - expect{ subject.invoke(:list, ['branches']) }.to output(%r{origin/feature-1-f1}).to_stdout + it 'branch list' do + expect{ subject.invoke(:branch, ['list']) }.to output(%r{origin/feature-1-f1}).to_stdout end - it 'inspect' do - expect{ subject.invoke(:inspect, ['feature-1-f1']) }.to output(/Feature: f1 on branch feature-1-f1/).to_stdout + it 'branch inspect' do + expect do + subject.invoke(:branch, ['inspect', 'feature-1-f1']) + end.to output(/Feature: f1 on branch feature-1-f1/).to_stdout end it 'deploy - noop' do expect{ subject.invoke(:deploy, ['feature-1-f1', '--provider', 'noop']) }.to_not raise_error @@ -49,10 +52,9 @@ context 'Git Commands', git: true do it 'exits 11 for invalid repositories' do - MiqFlow::Settings.update_git('https://github.com/invalid/not_a_repo.git', nil, nil, nil) - expect{ subject.invoke(:list, ['branches']) }.to raise_error(MiqFlow::GitError) + MiqFlow::Config.update_git('https://github.com/invalid/not_a_repo.git', nil, nil, nil) + expect{ subject.invoke(:branch, ['list']) }.to raise_error(MiqFlow::GitError) end - it{ is_expected().to be_truthy } end context 'Rake Commands: Docker', git: true, docker: true do @@ -62,8 +64,8 @@ end shared_examples_for 'ManageIQ API' do - it 'list miq' do - expect{ subject.invoke(:list, ['domains']).to_output(/ManageIQ/).to_stdout } + it 'domain list' do + expect{ subject.invoke(:domain, ['list']).to_output(/ManageIQ/).to_stdout } end end @@ -86,19 +88,19 @@ it_behaves_like('ManageIQ API') it 'handles 500 codes' do server_stub.to_return(status: 500) - expect{ subject.invoke(:list, ['domains']) }.to raise_error(MiqFlow::BadResponseError) + expect{ subject.invoke(:domain, ['list']) }.to raise_error(MiqFlow::BadResponseError) end it 'handles invalid Credentials' do server_stub.to_return(status: 403) - expect{ subject.invoke(:list, ['domains']) }.to raise_error(MiqFlow::BadResponseError) + expect{ subject.invoke(:domain, ['list']) }.to raise_error(MiqFlow::BadResponseError) end it 'handles connection reset' do server_stub.to_raise(Errno::ECONNREFUSED) - expect{ subject.invoke(:list, ['domains']) }.to raise_error(MiqFlow::ConnectionError) + expect{ subject.invoke(:domain, ['list']) }.to raise_error(MiqFlow::ConnectionError) end it 'handles timeout' do server_stub.to_timeout - expect{ subject.invoke(:list, ['domains']) }.to raise_error(MiqFlow::ConnectionError) + expect{ subject.invoke(:domain, ['list']) }.to raise_error(MiqFlow::ConnectionError) end end end diff --git a/spec/miq_utils_spec.rb b/spec/miq_utils_spec.rb new file mode 100644 index 0000000..b10084f --- /dev/null +++ b/spec/miq_utils_spec.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +require 'spec_helper' +RSpec.describe MiqFlow::MiqMethods::MiqUtils do + subject{ Object.new.extend(MiqFlow::MiqMethods::MiqUtils) } + context 'name_from_branch()' do + let!(:reset_naming){ MiqFlow::Config.update_naming(['-', '/'], 1) } + it 'defaults to TYPE-NAME-description syntax' do + name = subject.name_from_branch('feature-f1-description') + expect(name).to match('f1') + end + it 'can be used with TYPE-REF-NAME-description syntax' do + name = subject.name_from_branch('feature-1-f1-my-awsome-feature', index: 2) + expect(name).to match('f1') + end + it 'is not confused by underscores' do + name = subject.name_from_branch('feature/f1_part1-my_awsome_feature') + expect(name).to match('f1_part1') + end + it 'can use different separators' do + name = subject.name_from_branch('feature_f1-part1_my_awsome_feature', separator: ['_']) + expect(name).to match('f1-part1') + end + it 'replaces invalid characters' do + name = subject.name_from_branch('feature-f!_p@r=1-my_awsome_feature') + expect(name).to match('f__p_r_1') + end + it 'doe nothing if no separator present' do + name = subject.name_from_branch('my_awsome_feature') + expect(name).to match('my_awsome_feature') + end + end +end