class Object
Public Instance Methods
apache_site(*args)
click to toggle source
# File lib/geordi/commands/apache_site.rb, line 2 def apache_site(*args) site = args.shift old_cwd = Dir.pwd Dir.chdir '/etc/apache2/sites-available/' # show available sites if no site was passed as argument unless site puts 'ERROR: Argument site is missing.' puts 'Please call: apache-site my-site' puts puts 'Available sites:' Dir.new('.').each do |file| puts "- #{file}" if file != '.' && file != '..' end exit end has_default = File.exist?('default') exec "sudo a2dissite \*; sudo a2ensite #{'default ' if has_default}#{site} && sudo apache2ctl restart" Dir.chdir old_cwd end
branch()
click to toggle source
# File lib/geordi/commands/branch.rb, line 11 def branch require 'geordi/gitpt' Gitpt.new.run_branch(from_master: options.from_master) end
bundle_install()
click to toggle source
# File lib/geordi/commands/bundle_install.rb, line 2 def bundle_install if File.exist?('Gemfile') && !system('bundle check > /dev/null 2>&1') Interaction.announce 'Bundling' Util.run!('bundle install') end end
capistrano(*args)
click to toggle source
# File lib/geordi/commands/capistrano.rb, line 6 def capistrano(*args) targets = Dir['config/deploy/*.rb'].map { |file| File.basename(file, '.rb') }.sort Interaction.note 'Found the following deploy targets:' puts targets Interaction.prompt('Continue?', 'n', /y|yes/) || Interaction.fail('Cancelled.') targets << nil if targets.empty? # default target targets.each do |stage| Interaction.announce 'Target: ' + (stage || '(default)') command = "bundle exec cap #{stage} " + args.join(' ') Interaction.note_cmd command Util.run!(command, fail_message: 'Capistrano failed. Have a look!') end end
chromedriver_update()
click to toggle source
# File lib/geordi/commands/chromedriver_update.rb, line 16 def chromedriver_update require 'geordi/chromedriver_updater' ChromedriverUpdater.new.run(options) end
clean()
click to toggle source
# File lib/geordi/commands/clean.rb, line 2 def clean Interaction.announce 'Removing tempfiles' for pattern in %w[ webrat-* capybara-* tmp/webrat-* tmp/capybara-* tmp/rtex/* log/*.log ] Interaction.note pattern puts `rm -vfR #{pattern}` end Interaction.announce 'Finding recursively and removing backup files' %w[*~].each do |pattern| Interaction.note pattern `find . -name #{pattern} -exec rm {} ';'` end end
commit(*git_args)
click to toggle source
# File lib/geordi/commands/commit.rb, line 11 def commit(*git_args) require 'geordi/gitpt' Gitpt.new.run_commit(git_args) end
console(target = 'development', *_args)
click to toggle source
# File lib/geordi/commands/console.rb, line 15 def console(target = 'development', *_args) require 'geordi/remote' if target == 'development' invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' Interaction.announce 'Opening a local Rails console' command = Util.console_command(target) Util.run!(command) else Interaction.announce 'Opening a Rails console on ' + target Geordi::Remote.new(target).console(options) end end
create_database_yml()
click to toggle source
# File lib/geordi/commands/create_database_yml.rb, line 2 def create_database_yml real_yml = 'config/database.yml' sample_yml = 'config/database.sample.yml' if File.exist?(sample_yml) && !File.exist?(real_yml) Interaction.announce 'Creating ' + real_yml sample = File.read(sample_yml) adapter = sample.match(/adapter: (\w+)/).captures.first print "Please enter your #{adapter} password: " db_password = STDIN.gets.strip real = sample.gsub(/password:.*$/, "password: #{db_password}") File.open(real_yml, 'w') { |f| f.write(real) } Interaction.note "Created #{real_yml}." end end
create_databases()
click to toggle source
# File lib/geordi/commands/create_databases.rb, line 2 def create_databases invoke_geordi 'create_database_yml' invoke_geordi 'bundle_install' Interaction.announce 'Creating databases' if File.exist?('config/database.yml') command = [] command << Util.binstub_or_fallback('rake') command << 'db:create:all' command << 'parallel:create' if Util.file_containing?('Gemfile', /parallel_tests/) Util.run!(command) else puts 'config/database.yml does not exist. Nothing to do.' end end
cucumber(*args)
click to toggle source
# File lib/geordi/commands/cucumber.rb, line 27 def cucumber(*args) if args.empty? # This is not testable as there is no way to stub `git` :( if options.modified? modified_features = `git status --short`.split("\n").map do |line| indicators = line.slice!(0..2) # Remove leading indicators line if line.include?('.feature') && !indicators.include?('D') end.compact args = modified_features end if options.containing matching_features = `grep -lri '#{options.containing}' --include=*.feature features/`.split("\n") args = matching_features.uniq end end if File.directory?('features') require 'geordi/cucumber' settings = Geordi::Settings.new invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' if settings.auto_update_chromedriver invoke_geordi 'chromedriver_update', quiet_if_matching: true end cmd_opts, files = args.partition { |f| f.start_with? '-' } cmd_opts << '--format' << 'pretty' << '--backtrace' if options.debug # Parallel run of all given features + reruns ############################## Interaction.announce 'Running features' normal_run_successful = Geordi::Cucumber.new.run(files, cmd_opts, verbose: options.verbose) unless normal_run_successful cmd_opts << '--profile' << 'rerun' # Reruns (options.rerun + 1).times do |i| Interaction.fail 'Features failed.' if i == options.rerun # All reruns done? Interaction.announce "Rerun ##{i + 1} of #{options.rerun}" break if Geordi::Cucumber.new.run([], cmd_opts, verbose: options.verbose, parallel: false) end end Interaction.success 'Features green.' else Interaction.note 'Cucumber not employed.' end end
delete_dumps(*locations)
click to toggle source
# File lib/geordi/commands/delete_dumps.rb, line 12 def delete_dumps(*locations) Interaction.announce 'Retrieving dump files' dump_files = [] if locations.empty? locations = [ File.join(Dir.home, 'dumps'), Dir.pwd ] end locations.map! &File.method(:expand_path) Interaction.note "Looking in #{locations.join(', ')}" locations.each do |dir| directory = File.expand_path(dir) unless File.directory? File.realdirpath(directory) Interaction.warn "Directory #{directory} does not exist. Skipping." next end dump_files.concat Dir.glob("#{directory}/**/*.dump") end deletable_dumps = dump_files.flatten.uniq.sort.select &File.method(:file?) if deletable_dumps.empty? Interaction.warn 'No dump files found.' else puts deletable_dumps Interaction.prompt('Delete these files?', 'n', /y|yes/) || Interaction.fail('Cancelled.') deletable_dumps.each &File.method(:delete) Interaction.success 'Done.' end end
deploy(target_stage = nil)
click to toggle source
# File lib/geordi/commands/deploy.rb, line 38 def deploy(target_stage = nil) # Set/Infer default values branch_stage_map = { 'master' => 'staging', 'production' => 'production' } if target_stage && !Util.deploy_targets.include?(target_stage) # Target stage autocompletion from available stages target_stage = Util.deploy_targets.find { |t| t.start_with? target_stage } target_stage || Interaction.warn('Given deployment stage not found') end # Ask for required information target_stage ||= Interaction.prompt 'Deployment stage:', branch_stage_map.fetch(Util.current_branch, 'staging') if options.current_branch stage_file = "config/deploy/#{target_stage}.rb" Util.file_containing?(stage_file, 'DEPLOY_BRANCH') || Interaction.fail(<<~ERROR) To deploy from the current branch, configure #{stage_file} to respect the environment variable DEPLOY_BRANCH. Example: set :branch, ENV['DEPLOY_BRANCH'] || 'master' ERROR source_branch = target_branch = Util.current_branch else source_branch = Interaction.prompt 'Source branch:', Util.current_branch target_branch = Interaction.prompt 'Deploy branch:', branch_stage_map.invert.fetch(target_stage, 'master') end merge_needed = (source_branch != target_branch) push_needed = merge_needed || `git cherry -v | wc -l`.strip.to_i > 0 push_needed = false if Util.testing? # Hard to test Interaction.announce "Checking whether your #{source_branch} branch is ready" ############ Util.run!("git checkout #{source_branch}") if (`git status -s | wc -l`.strip != '0') && !Util.testing? Interaction.warn "Your #{source_branch} branch holds uncommitted changes." Interaction.prompt('Continue anyway?', 'n', /y|yes/) || raise('Cancelled.') else Interaction.note 'All good.' end if merge_needed Interaction.announce "Checking what's in your #{target_branch} branch right now" ####### Util.run!("git checkout #{target_branch} && git pull") end Interaction.announce 'You are about to:' ################################################# Interaction.note "Merge branch #{source_branch} into #{target_branch}" if merge_needed if push_needed Interaction.note 'Push these commits:' if push_needed Util.run!("git --no-pager log origin/#{target_branch}..#{source_branch} --oneline") end Interaction.note "Deploy to #{target_stage}" Interaction.note "From current branch #{source_branch}" if options.current_branch if Interaction.prompt('Go ahead with the deployment?', 'n', /y|yes/) puts git_call = [] git_call << "git merge #{source_branch}" if merge_needed git_call << 'git push' if push_needed invoke_geordi 'bundle_install' capistrano_call = "cap #{target_stage} deploy" capistrano_call << ':migrations' unless Util.gem_major_version('capistrano') == 3 || options.no_migrations capistrano_call = "bundle exec #{capistrano_call}" if Util.file_containing?('Gemfile', /capistrano/) capistrano_call = "DEPLOY_BRANCH=#{source_branch} #{capistrano_call}" if options.current_branch if git_call.any? Util.run!(git_call.join(' && '), show_cmd: true) end Util.run!(capistrano_call, show_cmd: true) Interaction.success 'Deployment complete.' else Util.run!("git checkout #{source_branch}") Interaction.fail 'Deployment cancelled.' end end
drop_databases()
click to toggle source
# File lib/geordi/commands/drop_databases.rb, line 23 def drop_databases require 'geordi/db_cleaner' Interaction.fail '-P and -M are mutually exclusive' if options.postgres_only && options.mysql_only mysql_flags = nil postgres_flags = nil unless options.mysql.nil? begin mysql_port = Integer(options.mysql) mysql_flags = "--port=#{mysql_port} --protocol=TCP" rescue AttributeError unless File.exist? options.mysql Interaction.fail "Path #{options.mysql} is not a valid MySQL socket" end mysql_flags = "--socket=#{options.mysql}" end end unless options.postgres.nil? postgres_flags = "--port=#{options.postgres}" end extra_flags = { 'mysql' => mysql_flags, 'postgres' => postgres_flags } cleaner = DBCleaner.new(extra_flags) cleaner.clean_mysql unless options.postgres_only cleaner.clean_postgres unless options.mysql_only end
dump(target = nil, *_args)
click to toggle source
# File lib/geordi/commands/dump.rb, line 24 def dump(target = nil, *_args) require 'geordi/dump_loader' require 'geordi/remote' database = options[:database] ? "#{options[:database]} " : '' if target.nil? if options.load # validate load option Interaction.fail 'Missing a dump file.' if options.load == 'load' File.exist?(options.load) || raise('Could not find the given dump file: ' + options.load) loader = DumpLoader.new(options.load) Interaction.announce "Sourcing dump into the #{loader.config['database']} db" loader.load Interaction.success "Your #{loader.config['database']} database has now the data of #{options.load}." else Interaction.announce 'Dumping the development database' Util.run!("dumple development #{database}") Interaction.success "Successfully dumped the #{database}development database." end else database_label = options[:database] ? " (#{database}database)" : "" Interaction.announce "Dumping the database of #{target}#{database_label}" dump_path = Geordi::Remote.new(target).dump(options) if options.load loader = DumpLoader.new(dump_path) Interaction.announce "Sourcing dump into the #{loader.config['database']} db" loader.load Util.run! "rm #{dump_path}" Interaction.note "Dump file removed" Interaction.success "Your #{loader.config['database']} database has now the data of #{target}#{database_label}." end end end
migrate()
click to toggle source
# File lib/geordi/commands/migrate.rb, line 10 def migrate invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' Interaction.announce 'Migrating' if File.directory?('db/migrate') if Util.file_containing?('Gemfile', /parallel_tests/) Interaction.note 'Development and parallel test databases' puts Util.run!([Util.binstub_or_fallback('rake'), 'db:migrate', 'parallel:prepare']) else invoke_geordi 'rake', 'db:migrate' end else Interaction.note 'No migrations directory found.' end end
png_optimize(path)
click to toggle source
# File lib/geordi/commands/png_optimize.rb, line 10 def png_optimize(path) require 'fileutils' Interaction.announce 'Optimizing .png files' if `which pngcrush`.strip.empty? Interaction.fail 'Please install pngcrush first (sudo apt-get install pngcrush)' end po = PngOptimizer.new if File.directory?(path) po.batch_optimize_inplace(path) elsif File.file?(path) po.optimize_inplace(path) else Interaction.fail 'Neither directory nor file: ' + path end Interaction.success 'PNG optimization completed.' end
rake(*args)
click to toggle source
# File lib/geordi/commands/rake.rb, line 12 def rake(*args) invoke_geordi 'bundle_install' %w[development test cucumber].each do |env| # update long_desc when changing this if File.exist? "config/environments/#{env}.rb" command = [] command << Util.binstub_or_fallback('rake') command += args command << "RAILS_ENV=#{env}" Util.run!(command, show_cmd: true) end end end
remove_executable_flags()
click to toggle source
# File lib/geordi/commands/remove_executable_flags.rb, line 2 def remove_executable_flags Interaction.announce 'Removing executable-flags' patterns = %w[ *.rb *.html *.erb *.haml *.yml *.css *.sass *.rake *.png *.jpg *.gif *.pdf *.txt *.rdoc *.feature Rakefile VERSION README Capfile ] patterns.each do |pattern| Interaction.note pattern `find . -name "#{pattern}" -exec chmod -x {} ';'` end Interaction.success 'Done.' end
rspec(*files)
click to toggle source
# File lib/geordi/commands/rspec.rb, line 11 def rspec(*files) if File.exist?('spec/spec_helper.rb') invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' Interaction.announce 'Running specs' if Util.file_containing?('Gemfile', /parallel_tests/) && files.empty? Interaction.note 'All specs at once (using parallel_tests)' Util.run!([Util.binstub_or_fallback('rake'), 'parallel:spec'], fail_message: 'Specs failed.') else # tell which specs will be run if files.empty? files << 'spec/' Interaction.note 'All specs in spec/' else Interaction.note 'Only: ' + files.join(', ') end command = if File.exist?('script/spec') ['bundle exec spec -c'] # RSpec 1 else [Util.binstub_or_fallback('rspec')] end command << '-r rspec_spinner -f RspecSpinner::Bar' if Util.file_containing?('Gemfile', /rspec_spinner/) command << files.join(' ') puts Util.run!(command.join(' '), fail_message: 'Specs failed.') end else Interaction.note 'RSpec not employed.' end end
security_update(step = 'prepare')
click to toggle source
# File lib/geordi/commands/security_update.rb, line 30 def security_update(step = 'prepare') case step when 'prepare' Interaction.announce 'Preparing for security update' Interaction.warn 'Please read https://makandracards.com/makandra/1587 before applying security updates!' Interaction.note 'About to checkout production and pull.' Interaction.prompt('Continue?', 'y', /y|yes/) || Interaction.fail('Cancelled.') Util.run!('git checkout production', show_cmd: true) Util.run!('git pull', show_cmd: true) Interaction.success 'Successfully prepared for security update' puts Interaction.note 'Please apply the security update now and commit your changes.' Interaction.note 'When you are done, run `geordi security-update finish`.' when 'f', 'finish' # ensure everything is committed if Util.testing? puts 'Util.run! git status --porcelain' else `git status --porcelain`.empty? || Interaction.fail('Please commit your changes before finishing the update.') end Interaction.announce 'Finishing security update' Interaction.note 'Working directory clean.' Interaction.prompt('Have you successfully run all tests?', 'n', /y|yes/) || Interaction.fail('Please run tests first.') Interaction.note 'About to: push production, checkout & pull master, merge production, push master.' Interaction.prompt('Continue?', 'n', /y|yes/) || Interaction.fail('Cancelled.') Util.run!('git push', show_cmd: true) Util.run!('git checkout master', show_cmd: true) Util.run!('git pull', show_cmd: true) Util.run!('git merge production', show_cmd: true) Util.run!('git push', show_cmd: true) Interaction.announce 'Deployment' deploy = (Util.gem_major_version('capistrano') == 3) ? 'deploy' : 'deploy:migrations' all_deploy_targets = Util.deploy_targets Interaction.fail 'There are no deploy targets!' if all_deploy_targets.empty? if all_deploy_targets.include?('staging') Interaction.note 'There is a staging environment.' Interaction.prompt('Deploy staging now?', 'y', /y|yes/) || Interaction.fail('Cancelled.') Interaction.announce 'Deploy staging' Util.run! "bundle exec cap staging #{deploy}", show_cmd: true Interaction.prompt('Is the deployment log okay and the application is still running on staging?', 'y', /y|yes/) || Interaction.fail('Please fix the deployment issues on staging before you continue.') else Interaction.note 'There is no staging environment.' end deploy_targets_without_staging = all_deploy_targets.select { |target| target != 'staging' } if deploy_targets_without_staging.empty? Interaction.note 'There are no other stages.' else puts Interaction.note 'Found the following other stages:' puts deploy_targets_without_staging puts Interaction.prompt('Deploy other stages now?', 'y', /y|yes/) || Interaction.fail('Cancelled.') deploy_targets_without_staging.each do |target| Interaction.announce "Deploy #{target}" Util.run!("bundle exec cap #{target} #{deploy}", show_cmd: true) end Interaction.prompt('Is the application still running on all other stages and the logs are okay?', 'y', /y|yes/) || Interaction.fail('Please fix the application immediately!') end Interaction.success 'Successfully pushed and deployed security update' puts Interaction.note 'Now send an email to customer and project lead, informing them about the update.' Interaction.note 'Do not forget to make a joblog on a security budget, if available.' end end
server(port = nil)
click to toggle source
# File lib/geordi/commands/server.rb, line 8 def server(port = nil) invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' require 'geordi/util' Interaction.announce 'Booting a development server' port ||= options.port Interaction.note "URL: http://#{File.basename(Dir.pwd)}.vcap.me:#{port}" puts command = Util.server_command command << ' -b 0.0.0.0' if options.public command << ' -p ' << port Util.run!(command) end
setup()
click to toggle source
# File lib/geordi/commands/setup.rb, line 17 def setup if File.exist? 'bin/setup' Interaction.announce 'Running bin/setup' Interaction.note "Geordi's own setup routine is skipped" Util.run!('bin/setup') else invoke_geordi 'create_databases' invoke_geordi 'migrate' end Interaction.success 'Successfully set up the project.' invoke_geordi 'dump', options.dump, load: true if options.dump invoke_geordi 'tests' if options.test end
shelll(target, *_args)
click to toggle source
This method has a triple 'l' because :shell is a Thor reserved word. However, it can still be called with `geordi shell` :)
# File lib/geordi/commands/shell.rb, line 15 def shelll(target, *_args) require 'geordi/remote' Interaction.announce 'Opening a shell on ' + target Geordi::Remote.new(target).shell(options) end
tests(*args)
click to toggle source
# File lib/geordi/commands/tests.rb, line 10 def tests(*args) if args.any? args, opts = Thor::Options.split(args) error_message = "When passing arguments, the first argument must be either an RSpec or a Cucumber path." if args.empty? Interaction.fail error_message elsif args.first.start_with? 'spec' invoke 'rspec', args, opts elsif args.first.start_with? 'features' invoke 'cucumber', args, opts else Interaction.fail error_message end else rake_result = invoke_geordi 'with_rake' # Since `rake` usually is configured to run all tests, only run them if `rake` # did not perform if rake_result == :did_not_perform invoke_geordi 'unit' invoke_geordi 'rspec' invoke_geordi 'cucumber' end Interaction.success 'Successfully ran tests.' end end
unit()
click to toggle source
# File lib/geordi/commands/unit.rb, line 2 def unit if File.exist?('test/test_helper.rb') invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' Interaction.announce 'Running Test::Unit' Util.run!([Util.binstub_or_fallback('rake'), 'test']) else Interaction.note 'Test::Unit not employed.' end end
update()
click to toggle source
# File lib/geordi/commands/update.rb, line 12 def update old_ruby_version = File.read('.ruby-version').chomp Interaction.announce 'Updating repository' Util.run!('git pull', show_cmd: true) ruby_version = File.read('.ruby-version').chomp ruby_version_changed = !ruby_version.empty? && (ruby_version != old_ruby_version) if ruby_version_changed puts Interaction.warn 'Ruby version changed during git pull. Please run again to use the new version.' exit(1) else invoke_geordi 'migrate' Interaction.success 'Successfully updated the project.' invoke_geordi 'dump', options.dump, load: true if options.dump invoke_geordi 'tests' if options.test end end
version()
click to toggle source
# File lib/geordi/commands/version.rb, line 2 def version require 'geordi/version' puts 'Geordi ' + Geordi::VERSION end
with_rake()
click to toggle source
# File lib/geordi/commands/with_rake.rb, line 2 def with_rake if Util.file_containing?('Rakefile', /^task.+default.+(spec|test|feature)/) invoke_geordi 'bundle_install' invoke_geordi 'yarn_install' Interaction.announce 'Running tests with `rake`' Util.run!(Util.binstub_or_fallback('rake')) else Interaction.note '`rake` does not run tests.' :did_not_perform end end
yarn_install()
click to toggle source
# File lib/geordi/commands/yarn_install.rb, line 3 def yarn_install if File.exist?('package.json') && !system('yarn check --integrity > /dev/null 2>&1') Interaction.announce 'Yarn install' Util.run!('yarn install') end end