orats 0.7.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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