orats 0.7.3 → 0.8.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/Gemfile +1 -1
  4. data/{LICENSE.txt → LICENSE} +21 -21
  5. data/README.md +51 -346
  6. data/Rakefile +1 -1
  7. data/bin/orats +5 -2
  8. data/lib/orats/argv_adjust.rb +61 -0
  9. data/lib/orats/cli.rb +53 -141
  10. data/lib/orats/cli_help/new +27 -0
  11. data/lib/orats/cli_help/nuke +19 -0
  12. data/lib/orats/commands/new/exec.rb +59 -0
  13. data/lib/orats/commands/new/rails.rb +197 -0
  14. data/lib/orats/commands/new/server.rb +67 -0
  15. data/lib/orats/commands/nuke.rb +66 -44
  16. data/lib/orats/common.rb +76 -0
  17. data/lib/orats/postgres.rb +90 -0
  18. data/lib/orats/process.rb +35 -0
  19. data/lib/orats/redis.rb +25 -0
  20. data/lib/orats/shell.rb +12 -0
  21. data/lib/orats/templates/auth.rb +96 -82
  22. data/lib/orats/templates/base.rb +115 -110
  23. data/lib/orats/templates/includes/new/rails/.env +28 -28
  24. data/lib/orats/templates/includes/new/rails/Gemfile +4 -4
  25. data/lib/orats/templates/includes/new/rails/config/{whenever.rb → schedule.rb} +0 -0
  26. data/lib/orats/ui.rb +33 -0
  27. data/lib/orats/version.rb +3 -2
  28. data/lib/orats.rb +2 -1
  29. data/orats.gemspec +7 -5
  30. data/test/integration/cli_test.rb +28 -177
  31. data/test/test_helper.rb +24 -9
  32. metadata +17 -29
  33. data/lib/orats/commands/common.rb +0 -146
  34. data/lib/orats/commands/diff/compare.rb +0 -106
  35. data/lib/orats/commands/diff/exec.rb +0 -60
  36. data/lib/orats/commands/diff/parse.rb +0 -66
  37. data/lib/orats/commands/inventory.rb +0 -100
  38. data/lib/orats/commands/playbook.rb +0 -60
  39. data/lib/orats/commands/project/exec.rb +0 -74
  40. data/lib/orats/commands/project/rails.rb +0 -162
  41. data/lib/orats/commands/project/server.rb +0 -57
  42. data/lib/orats/commands/role.rb +0 -70
  43. data/lib/orats/commands/ui.rb +0 -47
  44. data/lib/orats/templates/includes/inventory/group_vars/all.yml +0 -202
  45. data/lib/orats/templates/includes/inventory/hosts +0 -8
  46. data/lib/orats/templates/includes/playbook/Galaxyfile +0 -15
  47. data/lib/orats/templates/includes/playbook/common.yml +0 -23
  48. data/lib/orats/templates/includes/playbook/site.yml +0 -36
  49. data/lib/orats/templates/includes/role/.travis.yml +0 -19
  50. data/lib/orats/templates/includes/role/README.md +0 -62
  51. data/lib/orats/templates/includes/role/meta/main.yml +0 -123
  52. data/lib/orats/templates/includes/role/tests/inventory +0 -1
  53. data/lib/orats/templates/includes/role/tests/main.yml +0 -7
  54. data/lib/orats/templates/playbook.rb +0 -119
  55. data/lib/orats/templates/role.rb +0 -144
data/lib/orats/cli.rb CHANGED
@@ -1,169 +1,81 @@
1
1
  require 'thor'
2
- require 'orats/commands/project/exec'
3
- require 'orats/commands/inventory'
4
- require 'orats/commands/playbook'
5
- require 'orats/commands/role'
2
+ require 'orats/commands/new/exec'
6
3
  require 'orats/commands/nuke'
7
- require 'orats/commands/diff/exec'
4
+ require 'orats/version'
8
5
 
9
6
  module Orats
7
+ # the thor driven command line interface
10
8
  class CLI < Thor
11
- option :pg_location, default: 'localhost', aliases: '-l'
12
- option :pg_username, default: 'postgres', aliases: '-u'
13
- option :pg_password, required: true, aliases: '-p'
14
- option :redis_location, default: 'localhost', aliases: '-n'
15
- option :redis_password, default: '', aliases: '-d'
16
- option :template, default: '', aliases: '-m'
17
- option :custom, default: '', aliases: '-c'
18
- option :skip_ansible, type: :boolean, default: false, aliases: '-A'
19
- option :skip_server_start, type: :boolean, default: false, aliases: '-S'
20
- desc 'project TARGET_PATH [options]', ''
21
- long_desc <<-D
22
- `orats project target_path --pg-password supersecret` will create a new rails project and it will also create an ansible inventory to go with it by default.
23
-
24
- You must supply at least this flag:
25
-
26
- `--pg-password` to supply your development postgres password so the rails application can run database migrations
27
-
28
- Configuration:
29
-
30
- `--pg-location` to supply a custom postgres location [localhost]
31
-
32
- `--pg-username` to supply a custom postgres username [postgres]
33
-
34
- `--redis-location` to supply a custom redis location [localhost]
35
-
36
- `--redis-password` to supply your development redis password []
37
-
38
- Template features:
9
+ # if options are added through the .oratsrc file then we run the risk
10
+ # of having options not set for the command it was ran for
39
11
 
40
- `--template` accepts a template name which will get added in addition to the base template []
12
+ # for example the new command has a --template flag but the nuke command
13
+ # does not. thor will throw an error if you have --template in the
14
+ # .oratsrc config because it does not exist for the nuke command
41
15
 
42
- `--custom` will let you supply a custom template, a url or file is ok but urls must start with http or https []
16
+ # the code below gets a list of options that came from the .oratsrc file
17
+ # and compares them to the current options for the current command
43
18
 
44
- Project features:
19
+ # this is good, but now we need a way to somehow add these options into
20
+ # the command to fool thor into thinking they exist. we need to add
21
+ # the option somehow, thoughts?
45
22
 
46
- `--skip-ansible` skip creating the ansible related directories [false]
23
+ # for now none of the code below is in action and the readme explicitly
24
+ # says you can only store the postgres and redis credentials since
25
+ # the args only get inserted into the new and nuke commands
26
+ def initialize(args, local_options, config)
27
+ super
47
28
 
48
- `--skip-server-start` skip automatically running puma and sidekiq [false]
49
- D
29
+ matched_options = []
50
30
 
51
- def project(target_path)
52
- Commands::Project::Exec.new(target_path, options).init
53
- end
54
-
55
- desc 'inventory TARGET_PATH [options]', ''
56
- long_desc <<-D
57
- `orats inventory target_path` will create an ansible inventory.
58
- D
59
-
60
- def inventory(target_path)
61
- Commands::Inventory.new(target_path, options).init
62
- end
63
-
64
- option :custom, default: '', aliases: '-c'
65
- desc 'playbook TARGET_PATH [options]', ''
66
- long_desc <<-D
67
- `orats playbook target_path` will create an ansible playbook.
68
-
69
- Help:
31
+ config[:current_command].options.each do |key|
32
+ aliases = key[1].aliases
33
+ option = key[0].to_s.gsub('_', '-')
70
34
 
71
- If you pass in an existing playbook path it will update the role versions.
35
+ aliases.each do |item|
36
+ matched_options << item if local_options.join.include?(item)
37
+ end
72
38
 
73
- Template features:
74
-
75
- `--custom` will let you supply a custom template, a url or file is ok but urls
76
- must start with http or https []
77
- D
78
-
79
- def playbook(target_path)
80
- Commands::Playbook.new(target_path, options).init
39
+ matched_options << option if local_options.include?("--#{option}")
40
+ end
81
41
  end
82
42
 
83
- option :repo_name, default: '', aliases: '-r'
43
+ option :pg_location, default: 'localhost', aliases: '-l'
44
+ option :pg_username, default: 'postgres', aliases: '-u'
45
+ option :pg_password, default: '', aliases: '-p'
46
+ option :redis_location, default: 'localhost', aliases: '-n'
47
+ option :redis_password, default: '', aliases: '-d'
48
+ option :template, default: '', aliases: '-t'
84
49
  option :custom, default: '', aliases: '-c'
85
- desc 'role TARGET_PATH [options]', ''
86
- long_desc <<-D
87
- `orats role target_path` will create an ansible role suitable for the galaxy.
88
-
89
- Configuration:
90
-
91
- `--repo-name` if your github repo name is different than the full role name
92
-
93
- Template features:
94
-
95
- `--custom` will let you supply a custom template, a url or file is ok but urls
96
- must start with http or https []
97
- D
98
-
99
- def role(target_path)
100
- Commands::Role.new(target_path, options).init
50
+ option :skip_server_start, type: :boolean, default: false, aliases: '-S'
51
+ option :rc, default: ''
52
+ desc 'new PATH [options]', 'Create a new orats application'
53
+ long_desc File.read(File.join(File.dirname(__FILE__), 'cli_help/new'))
54
+ def new(target_path)
55
+ Commands::New::Exec.new(target_path, options).init
101
56
  end
102
57
 
103
- option :skip_data, type: :boolean, default: false, aliases: '-D'
58
+ option :pg_location, default: 'localhost', aliases: '-l'
59
+ option :pg_username, default: 'postgres', aliases: '-u'
60
+ option :pg_password, default: '', aliases: '-p'
61
+ option :redis_location, default: 'localhost', aliases: '-n'
104
62
  option :redis_password, default: '', aliases: '-d'
105
- desc 'nuke TARGET_PATH [options]', ''
106
- long_desc <<-D
107
- `orats nuke target_path` will delete the directory and optionally all data associated to it.
108
-
109
- Options:
110
-
111
- `--skip-data` will skip deleting app specific postgres databases and redis namespaces [false]
112
-
113
- `--redis-password` to supply your development redis password []
114
- D
115
-
63
+ option :skip_data, type: :boolean, default: false, aliases: '-D'
64
+ option :rc, default: ''
65
+ desc 'nuke PATH [options]', 'Delete a path and optionally its data'
66
+ long_desc File.read(File.join(File.dirname(__FILE__), 'cli_help/nuke'))
116
67
  def nuke(target_path)
117
68
  Commands::Nuke.new(target_path, options).init
118
69
  end
119
70
 
120
- option :galaxyfile, default: '', aliases: '-g'
121
- option :playbook, default: '', aliases: '-p'
122
- option :hosts, default: '', aliases: '-h'
123
- option :inventory, default: '', aliases: '-i'
124
- desc 'diff [options]', ''
125
- long_desc <<-D
126
- `orats diff` will run various comparisons on orats and your ansible files.
127
-
128
- Options:
129
-
130
- `--galaxyfile` to supply a galaxyfile for comparison []
131
-
132
- `--playbook` to supply a playbook directory/file for comparison []
133
-
134
- `--hosts` to supply a hosts file for comparison []
135
-
136
- `--inventory` to supply an inventory directory/file for comparison []
137
-
138
- Quality of life features:
139
-
140
- `--playbook` also accepts a playbook path, if you kept the
141
- default file names it will automatically compare both your Galaxyfile and
142
- site.yml files.
143
-
144
- `--inventory` also accepts an inventory path, if you kept the
145
- default file names it will automatically compare both your hosts and
146
- group_vars/all.yml files.
147
- D
148
-
149
- def diff
150
- Commands::Diff::Exec.new(nil, options).init
151
- end
152
-
153
- desc 'templates', ''
154
- long_desc <<-D
155
- `orats templates` will return a list of available orats templates.
156
- D
157
-
71
+ desc 'templates', 'Return a list of available templates'
72
+ long_desc 'Return a list of available built in templates.'
158
73
  def templates
159
- Commands::Project::Exec.new.list_templates
74
+ Commands::New::Exec.new.available_templates
160
75
  end
161
76
 
162
- desc 'version', ''
163
- long_desc <<-D
164
- `orats version` will print the current version.
165
- D
166
-
77
+ desc 'version', 'The current version of orats'
78
+ long_desc 'Print the current version.'
167
79
  def version
168
80
  puts "Orats version #{VERSION}"
169
81
  end
@@ -176,4 +88,4 @@ group_vars/all.yml files.
176
88
  caller_locations(0).any? { |backtrace| backtrace.label == 'invoke' }
177
89
  end
178
90
  end
179
- end
91
+ end
@@ -0,0 +1,27 @@
1
+ Create a new shiny rails app with quite a few best practices and opinions.
2
+
3
+ Development server credentials:
4
+
5
+ `--pg-location` to supply a custom postgres location [localhost]
6
+
7
+ `--pg-username` to supply a custom postgres username [postgres]
8
+
9
+ `--pg-password` to supply your postgres password to run migrations []
10
+
11
+ `--redis-location` to supply a custom redis location [localhost]
12
+
13
+ `--redis-password` to supply your redis password []
14
+
15
+ Options:
16
+
17
+ `--rc` to supply an .oratsrc file path to automatically populate credentials []
18
+
19
+ Template features:
20
+
21
+ `--template` to mix in an official orats template by supplying its name []
22
+
23
+ `--custom` to add your own template at the very end, a url or file is ok []
24
+
25
+ Project features:
26
+
27
+ `--skip-server-start` to skip automatically running puma and sidekiq [false]
@@ -0,0 +1,19 @@
1
+ Delete the target path and optionally all data associated to it.
2
+
3
+ Development server credentials:
4
+
5
+ `--pg-location` to supply a custom postgres location [localhost]
6
+
7
+ `--pg-username` to supply a custom postgres username [postgres]
8
+
9
+ `--pg-password` to supply your postgres password []
10
+
11
+ `--redis-location` to supply a custom redis location [localhost]
12
+
13
+ `--redis-password` to supply your redis password []
14
+
15
+ Options:
16
+
17
+ `--skip-data` to skip deleting app specific postgres and redis data [false]
18
+
19
+ `--rc` to supply an .oratsrc file path to automatically populate credentials []
@@ -0,0 +1,59 @@
1
+ require 'orats/common'
2
+ require 'orats/commands/new/rails'
3
+ require 'orats/commands/new/server'
4
+
5
+ module Orats
6
+ module Commands
7
+ module New
8
+ # entry point to the new command
9
+ class Exec < Common
10
+ include Rails
11
+ include Server
12
+
13
+ AVAILABLE_TEMPLATES = {
14
+ auth: 'add authentication and authorization'
15
+ }
16
+
17
+ def initialize(target_path = '', options = {})
18
+ super
19
+ end
20
+
21
+ def init
22
+ check_exit_conditions
23
+
24
+ rails_template 'base' do
25
+ rails_template_actions
26
+ end
27
+
28
+ orats_rails_template if template_exist?(@options[:template])
29
+ custom_rails_template unless @options[:custom].empty?
30
+ server_start
31
+ end
32
+
33
+ def available_templates
34
+ puts
35
+ log 'templates',
36
+ 'Add `-t TEMPLATE` to the new command to mixin a template',
37
+ :magenta
38
+ puts
39
+
40
+ AVAILABLE_TEMPLATES.each_pair do |key, value|
41
+ log key, value, :cyan
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def orats_to_local(source, dest)
48
+ includes_path = "#{base_path}/templates/includes"
49
+
50
+ unless Dir.exist?(File.dirname(dest))
51
+ system "mkdir -p #{File.dirname(dest)}"
52
+ end
53
+
54
+ system "cp #{includes_path}/#{source} #{dest}"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,197 @@
1
+ module Orats
2
+ module Commands
3
+ module New
4
+ # helper functions for the new::exec class
5
+ module Rails
6
+ def check_exit_conditions
7
+ exit_if_path_exists
8
+ exit_if_invalid_template
9
+ exit_if_invalid_system
10
+ exit_if_database_exists
11
+ end
12
+
13
+ def rails_template(command, flags = '')
14
+ orats_template = "--template #{base_path}/templates/#{command}.rb"
15
+
16
+ run "rails new #{@target_path} #{flags} --skip-bundle " + \
17
+ " #{orats_template unless command.empty?}"
18
+
19
+ yield if block_given?
20
+ end
21
+
22
+ def orats_rails_template
23
+ rails_template @options[:template], '--skip ' do
24
+ migrate_and_seed_database
25
+ end
26
+ end
27
+
28
+ def custom_rails_template
29
+ task 'Add custom template'
30
+
31
+ if @options[:custom].include('://')
32
+ url_to_string(@options[:custom])
33
+ else
34
+ file_to_string(@options[:custom])
35
+ end
36
+
37
+ rails_template '', "--skip --template #{@options[:custom]}"
38
+ end
39
+
40
+ def rails_template_actions
41
+ gsub_postgres_info
42
+ gsub_redis_info
43
+ gsub_app_path
44
+ gsub_readme
45
+
46
+ bundle_install
47
+ bundle_binstubs
48
+ spring_binstub
49
+
50
+ create_and_migrate_database
51
+ generate_home_page
52
+ generate_favicons
53
+ end
54
+
55
+ def gsub_postgres_info
56
+ task 'Update the postgres connection details'
57
+
58
+ gsub_file "#{@target_path}/.env", "DATABASE_HOST: 'localhost'",
59
+ "DATABASE_HOST: '#{@options[:pg_location]}'"
60
+ gsub_file "#{@target_path}/.env", ": 'postgres'",
61
+ ": '#{@options[:pg_username]}'"
62
+ gsub_file "#{@target_path}/.env", ": 'supersecrets'",
63
+ ": '#{@options[:pg_password]}'"
64
+
65
+ commit 'Update the postgres connection details'
66
+ end
67
+
68
+ def gsub_redis_info
69
+ task 'Update the redis connection details'
70
+
71
+ gsub_file "#{@target_path}/.env", "HE_PASSWORD: ''",
72
+ "HE_PASSWORD: '#{@options[:redis_password]}'"
73
+ gsub_file "#{@target_path}/.env", "CACHE_HOST: 'localhost'",
74
+ "CACHE_HOST: '#{@options[:redis_location]}'"
75
+
76
+ commit 'Update the redis connection details'
77
+ end
78
+
79
+ def gsub_app_path
80
+ task 'Update the app path'
81
+
82
+ gsub_file "#{@target_path}/.env", ": '/tmp/yourapp'",
83
+ ": '#{File.expand_path(@target_path)}'"
84
+
85
+ commit 'Update the app path'
86
+ end
87
+
88
+ def gsub_readme
89
+ task 'Update the readme'
90
+
91
+ gsub_file "#{@target_path}/README.md", 'VERSION', VERSION
92
+
93
+ commit 'Update the readme'
94
+ end
95
+
96
+ def bundle_install
97
+ task 'Run bundle install, this may take a while'
98
+ run_from @target_path, 'bundle install'
99
+
100
+ commit 'Add Gemfile.lock'
101
+ end
102
+
103
+ def bundle_binstubs
104
+ task 'Run bundle binstubs for a few gems'
105
+ run_from @target_path, 'bundle binstubs whenever puma sidekiq backup'
106
+
107
+ commit 'Add binstubs for the important gems'
108
+ end
109
+
110
+ def spring_binstub
111
+ task 'Run spring binstub'
112
+ run_from @target_path, 'bundle exec spring binstub --all'
113
+
114
+ commit 'Add spring binstubs for all of the bins'
115
+ end
116
+
117
+ def generate_home_page
118
+ kill_spring_servers
119
+
120
+ task 'Add pages controller with static page'
121
+ run_from @target_path, 'bundle exec rails g controller Pages home'
122
+
123
+ gsub_home_page
124
+ copy_home_page_views
125
+
126
+ commit 'Add pages controller with home page'
127
+ end
128
+
129
+ def generate_favicons
130
+ run_rake 'orats:favicons'
131
+
132
+ commit 'Add favicons'
133
+ end
134
+
135
+ def create_and_migrate_database
136
+ task 'Create and migrate the database'
137
+
138
+ create_database
139
+ run_rake 'db:migrate'
140
+
141
+ commit 'Add the database schema file'
142
+ end
143
+
144
+ def migrate_and_seed_database
145
+ run_rake 'db:migrate db:seed'
146
+
147
+ commit 'Update the database schema file'
148
+ end
149
+
150
+ def template_exist?(template)
151
+ Exec::AVAILABLE_TEMPLATES.include?(template.to_sym)
152
+ end
153
+
154
+ private
155
+
156
+ def gsub_home_page
157
+ gsub_file "#{@target_path}/config/routes.rb",
158
+ " # root 'welcome#index'", " root 'pages#home'"
159
+ gsub_file "#{@target_path}/config/routes.rb",
160
+ " get 'pages/home'\n\n", ''
161
+
162
+ gsub_file "#{@target_path}/test/controllers/pages_controller_" + \
163
+ 'test.rb', '"should get home"', "'expect home page'"
164
+ end
165
+
166
+ def copy_home_page_views
167
+ run_from @target_path, 'rm app/views/pages/home.html.erb'
168
+
169
+ orats_to_local 'new/rails/app/views/pages/home.html.erb',
170
+ "#{@target_path}/app/views/pages/home.html.erb"
171
+
172
+ gsub_file "#{@target_path}/app/views/pages/home.html.erb",
173
+ 'vVERSION', VERSION
174
+ end
175
+
176
+ def exit_if_invalid_template
177
+ template = @options[:template] || ''
178
+ task 'Check if template exists'
179
+
180
+ return if template.empty? || template_exist?(template)
181
+
182
+ error 'Cannot find template',
183
+ "'#{template}' is not a valid template name"
184
+
185
+ available_templates
186
+ exit 1
187
+ end
188
+
189
+ def kill_spring_servers
190
+ # rails generators will lock up if a spring server is running,
191
+ # so kill them all before continuing
192
+ system 'pkill -f spring'
193
+ end
194
+ end
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,67 @@
1
+ require 'socket'
2
+ require 'timeout'
3
+
4
+ module Orats
5
+ module Commands
6
+ module New
7
+ # handle starting the server
8
+ module Server
9
+ START_COMMAND = 'bundle exec foreman start'
10
+
11
+ def server_start
12
+ if @options[:skip_server_start]
13
+ message = 'Start your'
14
+ else
15
+ message = 'Starting'
16
+ end
17
+
18
+ display_notice message
19
+ attempt_to_start unless @options[:skip_server_start]
20
+ end
21
+
22
+ private
23
+
24
+ def display_notice(message)
25
+ results "#{message} server with the following commands",
26
+ 'command', "cd #{@target_path}"
27
+ log 'command', START_COMMAND, :white
28
+ end
29
+
30
+ def attempt_to_start
31
+ while port_taken?
32
+ error 'Failed to start server',
33
+ "Another application is using port 3000\n"
34
+ puts
35
+ exit 1 if no?('Would you like to try running ' + \
36
+ ' the server again? (y/N)', :cyan)
37
+ end
38
+
39
+ puts
40
+ run_from @target_path, START_COMMAND
41
+ end
42
+
43
+ def port_taken?
44
+ begin
45
+ start_server?
46
+ rescue Timeout::Error
47
+ false
48
+ end
49
+
50
+ false
51
+ end
52
+
53
+ def start_server?
54
+ Timeout.timeout(5) do
55
+ s = TCPSocket.new('localhost', 3000)
56
+ s.close
57
+
58
+ true
59
+ end
60
+
61
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
62
+ false
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end