orats 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,107 @@
1
+ module Orats
2
+ module Commands
3
+ module New
4
+ module Rails
5
+ def rails_template(command, flags = '')
6
+ exit_if_cannot_rails
7
+ exit_if_exists unless flags.index(/--skip/)
8
+
9
+ orats_template = "--template #{base_path}/templates/#{command}.rb"
10
+
11
+ run "rails new #{@active_path} #{flags} --skip-bundle #{orats_template unless command.empty?}"
12
+ yield if block_given?
13
+ end
14
+
15
+ def custom_rails_template
16
+ log_thor_task 'shell', 'Running custom rails template'
17
+
18
+ @options[:template].include?('://') ? url_to_string(@options[:template])
19
+ : file_to_string(@options[:template])
20
+
21
+ rails_template '', "--skip --template #{@options[:template]}"
22
+ end
23
+
24
+ def gsub_postgres_info
25
+ log_thor_task 'root', 'Changing the postgres information'
26
+ gsub_file "#{@active_path}/.env", 'DATABASE_HOST: localhost', "DATABASE_HOST: #{@options[:pg_location]}"
27
+ gsub_file "#{@active_path}/.env", ': postgres', ": #{@options[:pg_username]}"
28
+ gsub_file "#{@active_path}/.env", ': supersecrets', ": #{@options[:pg_password]}"
29
+
30
+ git_commit 'Change the postgres information'
31
+ end
32
+
33
+ def gsub_redis_info
34
+ log_thor_task 'root', 'Adding the redis password'
35
+ gsub_file "#{@active_path}/config/initializers/sidekiq.rb", '//', "//:#{ENV['CACHE_PASSWORD']}@"
36
+ gsub_file "#{@active_path}/.env", 'HE_PASSWORD: ', "HE_PASSWORD: #{@options[:redis_password]}"
37
+ gsub_file "#{@active_path}/.env", 'CACHE_HOST: localhost', "CACHE_HOST: #{@options[:redis_location]}"
38
+ gsub_file "#{@active_path}/config/application.rb", '# pass', 'pass'
39
+
40
+ git_commit 'Add the redis password'
41
+ end
42
+
43
+ def gsub_project_path
44
+ log_thor_task 'root', 'Changing the project path'
45
+ gsub_file "#{@active_path}/.env", ': /full/path/to/your/project', ": #{File.expand_path(@active_path)}"
46
+
47
+ git_commit 'Add the development project path'
48
+ end
49
+
50
+ def bundle_install
51
+ log_thor_task 'shell', 'Running bundle install, this may take a while'
52
+ run_from @active_path, 'bundle install'
53
+
54
+ git_commit 'Add gem lock file'
55
+ end
56
+
57
+ def bundle_binstubs
58
+ log_thor_task 'shell', 'Running bundle binstubs for a few gems'
59
+ run_from @active_path, 'bundle binstubs whenever puma sidekiq backup'
60
+
61
+ git_commit 'Add binstubs for the important gems'
62
+ end
63
+
64
+ def spring_binstub
65
+ log_thor_task 'shell', 'Running spring binstub'
66
+ run_from @active_path, 'bundle exec spring binstub --all'
67
+
68
+ git_commit 'Springify all of the bins'
69
+ end
70
+
71
+ def run_rake(command)
72
+ log_thor_task 'shell', 'Running rake commands'
73
+
74
+ run_from @active_path, "bundle exec rake #{command}"
75
+ end
76
+
77
+ def create_and_migrate_database
78
+ run_rake 'db:create:all db:migrate'
79
+ git_commit 'Add the database schema file'
80
+ end
81
+
82
+ private
83
+
84
+ def exit_if_cannot_rails
85
+ log_thor_task 'shell', 'Checking for rails'
86
+
87
+ has_rails = run('which rails', capture: true)
88
+
89
+ log_error 'error', 'Cannot access rails', 'question', 'Are you sure you have rails setup correctly?', true do
90
+ log_status_bottom 'tip', 'You can install it by running `gem install rails`', :white
91
+ end if has_rails.empty?
92
+
93
+ exit 1 if has_rails.empty?
94
+ end
95
+
96
+ def exit_if_exists
97
+ log_thor_task 'shell', 'Checking if a file or directory already exists'
98
+
99
+ if Dir.exist?(@active_path) || File.exist?(@active_path)
100
+ log_error 'error', 'A file or directory already exists at this location', 'path', @active_path
101
+ exit 1
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,72 @@
1
+ require 'orats/commands/common'
2
+
3
+ module Orats
4
+ module Commands
5
+ class Nuke < Common
6
+ def initialize(target_path = '', options = {})
7
+ super
8
+ end
9
+
10
+ def init
11
+ log_nuke_info
12
+ log_nuke_details unless @options[:skip_data]
13
+
14
+ confirmed_to_delete = yes?('Are you sure? (y/N)', :cyan); puts
15
+
16
+ if confirmed_to_delete
17
+ nuke_data unless @options[:skip_data]
18
+ nuke_directory
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def log_nuke_info
25
+ log_error 'nuke', 'You are about to permanently delete this directory',
26
+ 'path', File.expand_path(@target_path)
27
+ end
28
+
29
+ def log_nuke_details
30
+ rails_projects = []
31
+
32
+ valid_rails_directories.each { |rails_dir| rails_projects << File.basename(rails_dir) }
33
+ project_names = rails_projects.join(', ')
34
+
35
+ log_error 'nuke', 'You are about to permanently delete all postgres databases for',
36
+ 'databases', project_names, true
37
+
38
+ log_error 'nuke', 'You are about to permanently delete all redis namespaces for',
39
+ 'namespaces', project_names
40
+ end
41
+
42
+ def valid_rails_directories
43
+ rails_gemfiles =
44
+ run("find #{@active_path} -type f -name Gemfile | xargs grep -lE \"gem 'rails'|gem \\\"rails\\\"\"",
45
+ capture: true)
46
+
47
+ gemfile_paths = rails_gemfiles.split("\n")
48
+
49
+ gemfile_paths.map { |gemfile| File.dirname(gemfile) }
50
+ end
51
+
52
+ def nuke_data
53
+ valid_rails_directories.each do |directory|
54
+ log_thor_task 'root', 'Removing postgres databases'
55
+ run_from directory, 'bundle exec rake db:drop:all'
56
+
57
+ nuke_redis File.basename(directory)
58
+ end
59
+ end
60
+
61
+ def nuke_redis(namespace)
62
+ log_thor_task 'root', 'Removing redis keys'
63
+ run "redis-cli KEYS '#{namespace}:*' | xargs --delim='\n' redis-cli DEL"
64
+ end
65
+
66
+ def nuke_directory
67
+ log_thor_task 'root', 'Deleting directory'
68
+ run "rm -rf #{@active_path}"
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,100 @@
1
+ module Orats
2
+ module Commands
3
+ module Outdated
4
+ module Compare
5
+ def remote_to_local_gem_versions
6
+ log_remote_info 'gem', 'Comparing this version of orats to the latest orats version',
7
+ 'version', "Latest: #{@remote_gem_version}, Yours: v#{VERSION}"
8
+ end
9
+
10
+ def remote_to_local_galaxyfiles
11
+ galaxyfile_diff = @remote_galaxyfile - @local_galaxyfile
12
+ local_galaxyfile_as_string = @local_galaxyfile.join
13
+ local_galaxyfile_roles = @local_galaxyfile.size
14
+ roles_diff_count = galaxyfile_diff.size
15
+
16
+ log_status_top 'roles', "Comparing this version of orats' roles to the latest version:", :green
17
+
18
+ if roles_diff_count == 0
19
+ log_status_bottom 'message', "All #{local_galaxyfile_roles} roles are up to date", :yellow
20
+ else
21
+ log_status_bottom 'message', "There are #{roles_diff_count} differences", :yellow
22
+
23
+ galaxyfile_diff.each do |line|
24
+ name = line.split(',').first
25
+ status = 'outdated'
26
+ color = :yellow
27
+
28
+ unless local_galaxyfile_as_string.include?(name)
29
+ status = 'missing'
30
+ color = :red
31
+ end
32
+
33
+ log_status_bottom status, name, color, true
34
+ end
35
+
36
+ log_results 'The latest version of orats may benefit you', 'Check github to see if the changes interest you'
37
+ end
38
+ end
39
+
40
+ def remote_to_local(label, keyword, remote, local)
41
+ item_diff = remote - local
42
+ item_diff_count = item_diff.size
43
+
44
+ log_remote_info label, "Comparing this version of orats' #{label} to the latest version",
45
+ 'file', label == 'playbook' ? 'site.yml' : 'all.yml'
46
+
47
+ item_diff.each do |line|
48
+ log_status_bottom 'missing', line, :red, true unless local.include?(line)
49
+ end
50
+
51
+ if item_diff_count > 0
52
+ log_results "#{item_diff_count} new #{keyword} are available",
53
+ 'You may benefit from upgrading to the latest orats'
54
+ else
55
+ log_results 'Everything appears to be in order', "No missing #{keyword} were found"
56
+ end
57
+ end
58
+
59
+ def local_to_user(label, keyword, flag_path, local)
60
+ user = yield
61
+
62
+ log_local_info label, "Comparing this version of orats' #{label} to #{File.basename(flag_path)}",
63
+ 'path', flag_path
64
+
65
+ missing_count = log_unmatched(local, user, 'missing', :red)
66
+ extra_count = log_unmatched(user, local, 'extra', :yellow)
67
+
68
+ if missing_count > 0
69
+ log_results "#{missing_count} #{keyword} are missing",
70
+ "Your ansible run will likely fail with this #{label}"
71
+ else
72
+ log_results 'Everything appears to be in order', "No missing #{keyword} were found"
73
+ end
74
+
75
+ if extra_count > 0
76
+ log_results "#{extra_count} extra #{keyword} were detected:",
77
+ "No problem but remember to add them to future #{keyword}"
78
+ else
79
+ log_results "No extra #{keyword} were found:", "Extra #{keyword} are fine but you have none"
80
+ end
81
+ end
82
+
83
+ private
84
+
85
+ def log_unmatched(compare, against, label, color)
86
+ count = 0
87
+
88
+ compare.each do |item|
89
+ unless against.include?(item)
90
+ log_status_bottom label, item, color, true
91
+ count += 1
92
+ end
93
+ end
94
+
95
+ count
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,46 @@
1
+ require 'orats/commands/common'
2
+ require 'orats/version'
3
+ require 'orats/commands/outdated/parse'
4
+ require 'orats/commands/outdated/compare'
5
+
6
+ module Orats
7
+ module Commands
8
+ module Outdated
9
+ class Exec < Commands::Common
10
+ include Parse
11
+ include Compare
12
+
13
+ def initialize(target_path = '', options = {})
14
+ super
15
+
16
+ @remote_galaxyfile = galaxyfile url_to_string(@remote_paths[:galaxyfile])
17
+ @remote_inventory = inventory url_to_string(@remote_paths[:inventory])
18
+ @remote_playbook = playbook url_to_string(@remote_paths[:playbook])
19
+
20
+ @local_galaxyfile = galaxyfile file_to_string(@local_paths[:galaxyfile])
21
+ @local_inventory = inventory file_to_string(@local_paths[:inventory])
22
+ @local_playbook = playbook file_to_string(@local_paths[:playbook])
23
+ end
24
+
25
+ def init
26
+ remote_to_local_gem_versions
27
+ remote_to_local_galaxyfiles
28
+ remote_to_local 'inventory', 'variables', @remote_inventory, @local_inventory
29
+ remote_to_local 'playbook', 'roles', @remote_playbook, @local_playbook
30
+
31
+ unless @options[:playbook].empty?
32
+ local_to_user('playbook', 'roles', @options[:playbook], @local_playbook) do
33
+ playbook file_to_string(@options[:playbook])
34
+ end
35
+ end
36
+
37
+ unless @options[:inventory].empty?
38
+ local_to_user('inventory', 'variables', @options[:inventory], @local_inventory) do
39
+ inventory file_to_string(@options[:inventory])
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,62 @@
1
+ module Orats
2
+ module Commands
3
+ module Outdated
4
+ module Parse
5
+ def gem_version
6
+ "v#{url_to_string(@remote_paths[:version]).match(/'(.*)'/)[1..-1].first}"
7
+ end
8
+
9
+ def galaxyfile(contents)
10
+ contents.split
11
+ end
12
+
13
+ def inventory(contents)
14
+ # pluck out all of the values contained with {{ }}
15
+ ansible_variables = contents.scan(/\{\{([^{{}}]*)\}\}/)
16
+
17
+ # remove the leading space
18
+ ansible_variables.map! { |line| line.first[0] = '' }
19
+
20
+ # match every line that is not a comment and contains a colon
21
+ inventory_variables = contents.scan(/^[^#].*:/)
22
+
23
+ inventory_variables.map! do |line|
24
+ # only strip lines that need it
25
+ line.strip! if line.include?(' ') || line.include?("\n")
26
+
27
+ # get rid of the trailing colon
28
+ line.chomp(':')
29
+
30
+ # if a value of a certain variable has a colon then the regex
31
+ # picks this up as a match. only take the variable name
32
+ # if this happens to occur
33
+ line.split(':').first if line.include?(':')
34
+ end
35
+
36
+ (ansible_variables + inventory_variables).uniq.delete_if(&:empty?)
37
+ end
38
+
39
+ def playbook(contents)
40
+ roles = contents.scan(/^.*role:.*/)
41
+
42
+ roles.map! do |line|
43
+ line.strip! if line.include?(' ') || line.include?("\n")
44
+
45
+ role_parts = line.split('role:')
46
+
47
+ # start at the actual role name
48
+ line = role_parts[1]
49
+
50
+ if line.include?(',')
51
+ line = line.split(',').first
52
+ end
53
+
54
+ line.strip! if line.include?(' ')
55
+ end
56
+
57
+ roles.uniq
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,34 @@
1
+ require 'orats/commands/common'
2
+ require 'orats/commands/new/rails'
3
+
4
+ module Orats
5
+ module Commands
6
+ class Play < Common
7
+ include New::Rails
8
+
9
+ def initialize(target_path = '', options = {})
10
+ super
11
+ end
12
+
13
+ def init
14
+ return unless can_play?
15
+ rails_template 'play'
16
+ custom_rails_template unless @options[:template].empty?
17
+ end
18
+
19
+ private
20
+
21
+ def can_play?
22
+ log_thor_task 'shell', 'Checking for the ansible binary'
23
+
24
+ has_ansible = run('which ansible', capture: true)
25
+
26
+ log_error 'error', 'Cannot access ansible', 'question', 'Are you sure you have ansible setup correctly?', true do
27
+ log_status_bottom 'tip', 'http://docs.ansible.com/intro_installation.html', :white
28
+ end if has_ansible.empty?
29
+
30
+ !has_ansible.empty?
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,52 @@
1
+ module Orats
2
+ module Commands
3
+ module UI
4
+ include Thor::Shell
5
+
6
+ def log_thor_task(type, message)
7
+ puts
8
+ say_status type, "#{message}...", :yellow
9
+ puts '-'*80, ''; sleep 0.25
10
+ end
11
+
12
+ def log_status_top(type, message, color)
13
+ puts
14
+ say_status type, set_color(message, :bold), color
15
+ end
16
+
17
+ def log_status_bottom(type, message, color, strip_newline = false)
18
+ say_status type, message, color
19
+ puts unless strip_newline
20
+ end
21
+
22
+ def log_results(results, message)
23
+ log_status_top 'results', "#{results}:", :magenta
24
+ log_status_bottom 'message', message, :white
25
+ end
26
+
27
+ def log_error(top_label, top_message, bottom_label, bottom_message, strip_newline = false)
28
+ log_status_top top_label, "#{top_message}:", :red
29
+ log_status_bottom bottom_label, bottom_message , :yellow, strip_newline
30
+ yield if block_given?
31
+ end
32
+
33
+ def log_remote_info(top_label, top_message, bottom_label, bottom_message)
34
+ log_status_top top_label, "#{top_message}:", :green
35
+ log_status_bottom bottom_label, bottom_message, :yellow
36
+ end
37
+
38
+ def log_local_info(top_label, top_message, bottom_label, bottom_message)
39
+ log_status_top top_label, "#{top_message}:", :blue
40
+ log_status_bottom bottom_label, bottom_message, :cyan
41
+ end
42
+
43
+ def run_from(path, command)
44
+ run "cd #{path} && #{command} && cd -"
45
+ end
46
+
47
+ def git_commit(message)
48
+ run_from @active_path, "git add -A && git commit -m '#{message}'"
49
+ end
50
+ end
51
+ end
52
+ end