orats 0.5.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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