Top Level Namespace

Defined Under Namespace

Modules: Geordi Classes: PngOptimizer

Instance Method Summary collapse

Instance Method Details

#apache_site(*args) ⇒ Object



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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

#branchObject



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

def branch
  require 'geordi/gitlinear'
  Gitlinear.new.branch(from_master: options.from_master)

  Hint.did_you_know [
    :commit,
    [:branch, :from_master],
  ]
end

#bundle_installObject



2
3
4
5
6
7
# 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) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 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

  Hint.did_you_know [
    :deploy,
    :rake,
  ]
end

#chromedriver_updateObject



18
19
20
21
22
23
24
25
26
# File 'lib/geordi/commands/chromedriver_update.rb', line 18

def chromedriver_update
  require 'geordi/chromedriver_updater'

  ChromedriverUpdater.new.run(options)

  Hint.did_you_know [
    'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
  ] unless options.quiet_if_matching
end

#cleanObject



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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

  Hint.did_you_know [
    :remove_executable_flags,
  ]
end

#commit(*git_args) ⇒ Object



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

def commit(*git_args)
  require 'geordi/gitlinear'
  Gitlinear.new.commit(git_args)

  Hint.did_you_know [
    :branch,
    :deploy,
  ]
end

#console(target = 'development', *_args) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/geordi/commands/console.rb', line 17

def console(target = 'development', *_args)
  require 'geordi/remote'

  Hint.did_you_know [
    :shelll,
    [:console, :select_server],
    'You only need to type the unique prefix of a command to run it. `geordi con` will work as well.',
  ]

  if target == 'development'
    invoke_geordi 'bundle_install'
    invoke_geordi 'yarn_install'

    Interaction.announce 'Opening a local Rails console'

    command = Util.console_command(target)
    # Exec has better behavior on Ctrl + C
    Util.run!(command, exec: true)
  else
    Interaction.announce 'Opening a Rails console on ' + target

    Geordi::Remote.new(target).console(options)
  end
end

#create_database_ymlObject



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 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_databasesObject



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 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) ⇒ Object



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# 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, exit_on_failure: false
    end

    arguments = args
    arguments << '--format' << 'pretty' << '--backtrace' if options.debug

    # Parallel run of all given features + reruns ##############################
    Interaction.announce 'Running features'
    normal_run_successful = Geordi::Cucumber.new.run(arguments, verbose: options.verbose)

    unless normal_run_successful
      arguments << '--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(arguments, verbose: options.verbose, parallel: false)
      end
    end

    Interaction.success 'Features green.'

    Hint.did_you_know [
      :rspec,
      [:cucumber, :modified],
      [:cucumber, :containing],
      [:cucumber, :debug],
      [:cucumber, :rerun],
      'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
      'You only need to type the unique prefix of a command to run it. `geordi cuc` will work as well.',
    ]
  else
    Interaction.note 'Cucumber not employed.'
  end
end

#delete_dumps(*locations) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 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

  Hint.did_you_know [
    :clean,
    :drop_databases,
    :dump,
  ]
end

#deploy(target_stage = nil) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/geordi/commands/deploy.rb', line 39

def deploy(target_stage = nil)
  # Set/Infer default values
  branch_stage_map = { 'master' => 'staging', 'main' => '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

    deploy_branch = 'production' if target_stage == 'production'
    deploy_branch ||= Util.git_default_branch
    target_branch = Interaction.prompt 'Deploy branch:', deploy_branch
  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.'

    Hint.did_you_know [
      :capistrano,
      :security_update,
    ]
  else
    Util.run!("git checkout #{source_branch}")
    Interaction.fail 'Deployment cancelled.'
  end
end

#drop_databasesObject



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/geordi/commands/drop_databases.rb', line 28

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

  unless options.sudo
    Interaction.note 'Assuming your local user has permission to drop databases. Run with `--sudo` to use sudo.'
  end

  extra_flags = {
    'mysql' => mysql_flags,
    'postgres' => postgres_flags,
  }
  cleaner = DBCleaner.new(extra_flags, sudo: options.sudo)
  cleaner.clean_mysql unless options.postgres_only
  cleaner.clean_postgres unless options.mysql_only

  Hint.did_you_know [
    :delete_dumps,
  ]
end

#dump(target = nil, *_args) ⇒ Object



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/geordi/commands/dump.rb', line 30

def dump(target = nil, *_args)
  require 'geordi/dump_loader'
  require 'geordi/remote'
  database = options[:database] ? "#{options[:database]} " : ''

  if target.nil? # Local …
    if options.load # … dump loading
      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, options.database)

      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 # … dump creation
      Interaction.announce 'Dumping the development database'
      Util.run!("dumple development #{database}")
      Interaction.success "Successfully dumped the #{database}development database."
    end

  else # Remote dumping …
    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 # … and dump loading
      loader = DumpLoader.new(dump_path, options.database)

      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

  Hint.did_you_know [
    :delete_dumps,
    :drop_databases,
    :migrate,
    'Geordi can load a dump directly into the local database if passed a Capistrano stage and the option -l. See `geordi help dump`.',
  ]
end

#migrateObject



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/geordi/commands/migrate.rb', line 10

def migrate
  if File.directory?('db/migrate')
    invoke_geordi 'bundle_install'
    invoke_geordi 'yarn_install'
    Interaction.announce 'Migrating'

    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) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 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) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 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

  Hint.did_you_know [
    :capistrano,
  ]
end

#remove_executable_flagsObject



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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.'

  Hint.did_you_know [
    :clean,
  ]
end

#rspec(*files) ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/geordi/commands/rspec.rb', line 11

def rspec(*files)
  if File.exist?('spec/spec_helper.rb')
    require 'geordi/settings'

    settings = Geordi::Settings.new

    invoke_geordi 'bundle_install'
    invoke_geordi 'yarn_install'
    if settings.auto_update_chromedriver && Util.gem_available?('selenium-webdriver')
      invoke_geordi 'chromedriver_update', quiet_if_matching: true, exit_on_failure: false
    end

    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

    Hint.did_you_know [
      :cucumber,
      'Geordi can automatically keep chromedriver up-to-date. See `geordi help chromedriver-update`.',
      'You only need to type the unique prefix of a command to run it. `geordi rs` will work as well.',
    ]
  else
    Interaction.note 'RSpec not employed.'
  end
end

#security_update(step = 'prepare') ⇒ Object



11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/geordi/commands/security_update.rb', line 11

def security_update(step = 'prepare')
  master = Util.git_default_branch

  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.'
  else
    Interaction.fail "Unsupported step #{step.inspect}"
  end
end

#server(port = nil) ⇒ Object



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/geordi/commands/server.rb', line 8

def server(port = nil)
  Hint.did_you_know [
    [:server, :public],
  ]

  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)}.daho.im:#{port}"
  puts

  command = Util.server_command
  command << ' -b 0.0.0.0' if options.public
  command << ' -p ' << port
  Util.run!(command)
end

#setupObject



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 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.'

  Hint.did_you_know [
    :update,
    :security_update,
    [:setup, :dump],
    [:setup, :test],
  ] unless options.dump || options.test

  invoke_geordi 'dump', options.dump, load: true if options.dump
  invoke_geordi 'tests' if options.test
end

#shelll(target, *_args) ⇒ Object

This method has a triple ‘l’ because :shell is a Thor reserved word. However, it can still be called with ‘geordi shell` :)



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/geordi/commands/shell.rb', line 15

def shelll(target, *_args)
  require 'geordi/remote'

  Hint.did_you_know [
    :console,
    'You only need to type the unique prefix of a command to run it. `geordi sh` will work as well.',
  ]

  Interaction.announce 'Opening a shell on ' + target
  Geordi::Remote.new(target).shell(options)
end

#tests(*args) ⇒ Object



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 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
    else
      rspec_paths = args.select { |a| Util.rspec_path?(a) }
      cucumber_paths = args.select { |a| Util.cucumber_path?(a) }

      invoke('rspec', rspec_paths, opts) if rspec_paths.any?
      invoke('cucumber', cucumber_paths, opts) if cucumber_paths.any?
    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

  Hint.did_you_know [
    :deploy,
  ]
end

#unitObject



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/geordi/commands/unit.rb', line 8

def unit
  if File.exist?('test/test_helper.rb')
    invoke_geordi 'bundle_install'
    invoke_geordi 'yarn_install'

    Interaction.announce 'Running Test::Unit'

    if Util.file_containing?('Gemfile', /parallel_tests/)
      Interaction.note 'All unit tests at once (using parallel_tests)'
      Util.run!([Util.binstub_or_fallback('rake'), 'parallel:test'], fail_message: 'Test::Unit failed.')
    else
      Util.run!([Util.binstub_or_fallback('rake'), 'test'], fail_message: 'Test::Unit failed.')
    end
  else
    Interaction.note 'Test::Unit not employed.'
  end
end

#updateObject



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 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.'

    Hint.did_you_know [
      :setup,
      [:update, :dump],
      [:update, :test],
    ] unless options.dump || options.test

    invoke_geordi 'dump', options.dump, load: true if options.dump
    invoke_geordi 'tests' if options.test
  end

end

#versionObject



2
3
4
5
# File 'lib/geordi/commands/version.rb', line 2

def version
  require 'geordi/version'
  puts 'Geordi ' + Geordi::VERSION
end

#with_rakeObject



2
3
4
5
6
7
8
9
10
11
12
13
# 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_installObject



3
4
5
6
7
8
# File 'lib/geordi/commands/yarn_install.rb', line 3

def yarn_install
  if File.exist?('yarn.lock') && !system('yarn check --integrity > /dev/null 2>&1')
    Interaction.announce 'Yarn install'
    Util.run!('yarn install')
  end
end