redmine-installer 1.0.7 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +7 -0
  4. data/Gemfile +3 -15
  5. data/README.md +49 -177
  6. data/bin/redmine +4 -5
  7. data/lib/redmine-installer/backup.rb +13 -40
  8. data/lib/redmine-installer/cli.rb +92 -61
  9. data/lib/redmine-installer/command.rb +63 -117
  10. data/lib/redmine-installer/configuration.rb +148 -0
  11. data/lib/redmine-installer/database.rb +204 -0
  12. data/lib/redmine-installer/environment.rb +21 -0
  13. data/lib/redmine-installer/errors.rb +7 -0
  14. data/lib/redmine-installer/install.rb +37 -42
  15. data/lib/redmine-installer/logger.rb +83 -0
  16. data/lib/redmine-installer/package.rb +180 -0
  17. data/lib/redmine-installer/patches/ruby.rb +35 -0
  18. data/lib/redmine-installer/patches/tty.rb +16 -0
  19. data/lib/redmine-installer/profile.rb +24 -55
  20. data/lib/redmine-installer/redmine.rb +551 -0
  21. data/lib/redmine-installer/spec/spec.rb +81 -0
  22. data/lib/redmine-installer/task.rb +18 -77
  23. data/lib/redmine-installer/task_module.rb +12 -0
  24. data/lib/redmine-installer/upgrade.rb +51 -59
  25. data/lib/redmine-installer/utils.rb +46 -233
  26. data/lib/redmine-installer/version.rb +2 -4
  27. data/lib/redmine-installer.rb +69 -56
  28. data/redmine-installer.gemspec +20 -19
  29. data/spec/custom_matchers.rb +21 -0
  30. data/spec/installer_helper.rb +107 -0
  31. data/spec/installer_process.rb +82 -0
  32. data/spec/lib/backup_restore_spec.rb +81 -0
  33. data/spec/lib/install_spec.rb +125 -36
  34. data/spec/lib/upgrade_spec.rb +73 -52
  35. data/spec/packages/redmine-3.1.0.zip +0 -0
  36. data/spec/packages/redmine-3.2.0.zip +0 -0
  37. data/spec/packages/redmine-3.3.0-bad-migration.zip +0 -0
  38. data/spec/packages/redmine-3.3.0.zip +0 -0
  39. data/spec/packages/something-else.zip +0 -0
  40. data/spec/packages_helper.rb +19 -0
  41. data/spec/shared_contexts.rb +13 -0
  42. data/spec/spec_helper.rb +34 -18
  43. metadata +62 -63
  44. data/lib/redmine-installer/config_param.rb +0 -100
  45. data/lib/redmine-installer/error.rb +0 -5
  46. data/lib/redmine-installer/exec.rb +0 -158
  47. data/lib/redmine-installer/ext/module.rb +0 -7
  48. data/lib/redmine-installer/ext/string.rb +0 -15
  49. data/lib/redmine-installer/git.rb +0 -51
  50. data/lib/redmine-installer/helper.rb +0 -5
  51. data/lib/redmine-installer/helpers/generate_config.rb +0 -29
  52. data/lib/redmine-installer/locales/cs.yml +0 -147
  53. data/lib/redmine-installer/locales/en.yml +0 -154
  54. data/lib/redmine-installer/plugin.rb +0 -9
  55. data/lib/redmine-installer/plugins/base.rb +0 -24
  56. data/lib/redmine-installer/plugins/database.rb +0 -180
  57. data/lib/redmine-installer/plugins/email_sending.rb +0 -82
  58. data/lib/redmine-installer/plugins/redmine_plugin.rb +0 -82
  59. data/lib/redmine-installer/plugins/web_server.rb +0 -26
  60. data/lib/redmine-installer/step.rb +0 -16
  61. data/lib/redmine-installer/steps/backup.rb +0 -125
  62. data/lib/redmine-installer/steps/base.rb +0 -79
  63. data/lib/redmine-installer/steps/database_config.rb +0 -15
  64. data/lib/redmine-installer/steps/email_config.rb +0 -11
  65. data/lib/redmine-installer/steps/env_check.rb +0 -20
  66. data/lib/redmine-installer/steps/install.rb +0 -23
  67. data/lib/redmine-installer/steps/load_package.rb +0 -226
  68. data/lib/redmine-installer/steps/move_redmine.rb +0 -22
  69. data/lib/redmine-installer/steps/redmine_root.rb +0 -52
  70. data/lib/redmine-installer/steps/upgrade.rb +0 -57
  71. data/lib/redmine-installer/steps/validation.rb +0 -38
  72. data/lib/redmine-installer/steps/webserver_config.rb +0 -22
  73. data/spec/load_redmine.rb +0 -24
@@ -1,144 +1,90 @@
1
- require 'singleton'
1
+ require 'open3'
2
2
 
3
- module Redmine::Installer
3
+ module RedmineInstaller
4
4
  class Command
5
- include Singleton
6
- include Redmine::Installer::Utils
5
+ include Utils
7
6
 
8
- RAKE = 'bundle exec rake'
7
+ attr_reader :cmd, :title, :formatter
9
8
 
10
- def bundle_install(env)
11
- run('bundle install', get_bundle_env(env), :'command.bundle_install')
9
+ def initialize(cmd, title: nil)
10
+ @cmd = cmd
11
+ @title = title || cmd
12
+ @formatter = $SILENT_MODE ? SilentFormatter.new : FullFormatter.new
12
13
  end
13
14
 
14
- def rake_db_create(env)
15
- run(RAKE, 'db:create', get_rails_env(env), :'command.rake_db_create')
16
- end
15
+ def run
16
+ success = false
17
17
 
18
- def rake_db_migrate(env)
19
- run(RAKE, 'db:migrate', get_rails_env(env), :'command.rake_db_migrate')
20
- end
18
+ logger.std("--> #{cmd}")
21
19
 
22
- def rake_redmine_plugin_migrate(env)
23
- run(RAKE, 'redmine:plugins:migrate', get_rails_env(env), :'command.rake_redmine_plugin_migrate')
24
- end
20
+ formatter.print_title(title)
25
21
 
26
- def rake_generate_secret_token(env)
27
- run(RAKE, 'generate_secret_token', get_rails_env(env), :'command.rake_generate_secret_token')
28
- end
22
+ status = Open3.popen2e(cmd) do |input, output, wait_thr|
23
+ input.close
29
24
 
30
- private
25
+ output.each_line do |line|
26
+ logger.std(line)
27
+ formatter.print_line(line)
28
+ end
31
29
 
32
- def run(*args)
33
- _args = args.dup
30
+ wait_thr.value
31
+ end
34
32
 
35
- # Last element is title
36
- title = args.pop
37
- title = translate(title) if title.is_a?(Symbol)
38
- title = "--> <yellow>#{title}</yellow>"
39
- colorize(title)
33
+ success = status.success?
34
+ rescue => e
35
+ success = false
36
+ ensure
37
+ formatter.print_end(success)
38
+ end
40
39
 
41
- command = args.join(' ')
42
40
 
41
+ class BaseFormatter
42
+ include Utils
43
+ end
44
+
45
+ class FullFormatter < BaseFormatter
46
+
47
+ def print_title(title)
43
48
  puts '-->'
44
- puts title
49
+ puts "--> #{pastel.yellow(title)}"
45
50
  puts '-->'
46
- success = Kernel.system(command)
47
-
48
- unless success
49
- if confirm(:do_you_want_repeat_command, false)
50
- return run(*_args)
51
- else
52
- error(:command_exit_with_error, command: command)
53
- end
54
- end
51
+ end
55
52
 
56
- return success
53
+ def print_line(line)
54
+ puts line
57
55
  end
58
56
 
59
- def get_rails_env(env)
60
- if env.include?('production'); 'RAILS_ENV=production'
61
- elsif env.include?('development'); 'RAILS_ENV=development'
62
- elsif env.include?('test'); 'RAILS_ENV=test'
63
- else
64
- ''
65
- end
57
+ def print_end(*)
66
58
  end
67
59
 
68
- def get_bundle_env(env)
69
- if env.include?('production')
70
- '--without development test'
60
+ end
61
+
62
+ class SilentFormatter < BaseFormatter
63
+
64
+ def initialize
65
+ @output = ''
66
+ end
67
+
68
+ def print_title(title)
69
+ format = "[#{pastel.yellow(':spinner')}] #{title}"
70
+ @spinner = TTY::Spinner.new(format, success_mark: pastel.green('✔'), error_mark: pastel.red('✖'))
71
+ @spinner.auto_spin
72
+ end
73
+
74
+ def print_line(line)
75
+ @output << line
76
+ end
77
+
78
+ def print_end(success)
79
+ if success
80
+ @spinner.success
71
81
  else
72
- ''
82
+ @spinner.error
83
+ puts @output
73
84
  end
74
85
  end
75
86
 
87
+ end
88
+
76
89
  end
77
90
  end
78
-
79
- ##
80
- # Class for easier create complex command
81
- #
82
- # == Examples:
83
- #
84
- # Instead of this:
85
- # exec('rake redmine:plugins:migrate RAILS_ENV=production')
86
- #
87
- # you can write:
88
- # rake.plugin_migrate.production.run
89
- #
90
- # module Redmine::Installer
91
- # module Command
92
- # class Base
93
- # # Register main command only for child class
94
- # def self.command(cmd)
95
- # self.class_variable_set('@@command', cmd)
96
- # end
97
-
98
- # # Register new argument and method name
99
- # def self.add(name, cmd)
100
- # self.class_eval <<-EVAL
101
- # def #{name}
102
- # arguments << '#{cmd}'
103
- # self
104
- # end
105
- # EVAL
106
- # end
107
-
108
- # def initialize(command=nil)
109
- # @command = self.class.class_variable_get('@@command')
110
- # end
111
-
112
- # def arguments
113
- # @arguments ||= []
114
- # end
115
-
116
- # def command
117
- # %{#{@command} #{arguments.join(' ')}}
118
- # end
119
-
120
- # def run(title=nil, with_timer=false)
121
- # Redmine::Installer::Exec.new(command, title, with_timer).run
122
- # end
123
-
124
- # def repeatable_run(title=nil, with_timer=false)
125
- # Redmine::Installer::Exec.new(command, title, with_timer).repeatable_run
126
- # end
127
- # end
128
-
129
- # class Rake < Base
130
- # command 'bundle exec rake'
131
- # add 'db_create', 'db:create'
132
- # add 'db_migrate', 'db:migrate'
133
- # add 'generate_secret_token', 'generate_secret_token'
134
- # add 'redmine_plugin_migrate', 'redmine:plugins:migrate'
135
- # add 'production', 'RAILS_ENV=production'
136
- # end
137
-
138
- # class Bundle < Base
139
- # command 'bundle'
140
- # add 'install', 'install'
141
- # add 'production', '--without development test'
142
- # end
143
- # end
144
- # end
@@ -0,0 +1,148 @@
1
+ module RedmineInstaller
2
+ ##
3
+ # RedmineInstaller::Configuration
4
+ #
5
+ # For now, email is only configured.
6
+ #
7
+ class Configuration
8
+ extend Utils
9
+
10
+ def self.create_config(redmine)
11
+ # Maybe: enum_select
12
+ klass = prompt.select('Which service to use for email sending?') do |menu|
13
+ menu.default 4
14
+
15
+ menu.choice 'Custom configuration (SMTP)', CustomConfiguration
16
+ menu.choice 'Gmail', Gmail
17
+ menu.choice 'SendMail', SendMail
18
+ menu.choice 'Nothing', Nothing
19
+ end
20
+
21
+ # Get parameters and create configuration
22
+ database = klass.new(redmine)
23
+ database.get_parameters
24
+ database.make_config
25
+ database
26
+ end
27
+
28
+ class Base
29
+ include RedmineInstaller::Utils
30
+
31
+ def initialize(redmine)
32
+ @redmine = redmine
33
+ end
34
+
35
+ def get_parameters
36
+ @username = prompt.ask('Username:', required: true)
37
+ @password = prompt.mask('Password:', required: true)
38
+ end
39
+
40
+ def make_config
41
+ File.open(@redmine.configuration_yml_path, 'w') do |f|
42
+ f.puts(YAML.dump(build))
43
+ end
44
+ end
45
+
46
+ def build
47
+ {
48
+ 'default' => {
49
+ 'email_delivery' => {
50
+ 'delivery_method' => delivery_method,
51
+ "#{delivery_method}_settings" => delivery_settings
52
+ }
53
+ }
54
+ }
55
+ end
56
+
57
+ def delivery_method
58
+ :smtp
59
+ end
60
+
61
+ def delivery_settings
62
+ settings = {}
63
+
64
+ # Required
65
+ settings['address'] = @address
66
+ settings['port'] = @port
67
+
68
+ # Optional
69
+ settings['authentication'] = @authentication unless @authentication.to_s.empty?
70
+ settings['domain'] = @domain unless @domain.to_s.empty?
71
+ settings['user_name'] = @user_name unless @user_name.to_s.empty?
72
+ settings['password'] = @password unless @password.to_s.empty?
73
+ settings['enable_starttls_auto'] = @enable_starttls unless @enable_starttls.to_s.empty?
74
+ settings['openssl_verify_mode'] = @openssl_verify unless @openssl_verify.to_s.empty?
75
+
76
+ settings
77
+ end
78
+
79
+ def to_s
80
+ "<#{class_name} #{@username}@#{@address}:#{@port}>"
81
+ end
82
+
83
+ end
84
+
85
+ class Nothing < Base
86
+
87
+ def get_parameters(*) end
88
+ def make_config(*) end
89
+
90
+ def to_s(*)
91
+ "<Nothing>"
92
+ end
93
+
94
+ end
95
+
96
+ class Gmail < Base
97
+
98
+ def get_parameters
99
+ super
100
+ @address = 'smtp.gmail.com'
101
+ @port = 587
102
+ @domain = 'smtp.gmail.com'
103
+ @authentication = :plain
104
+ @enable_starttls = true
105
+ end
106
+
107
+ end
108
+
109
+ class CustomConfiguration < Base
110
+
111
+ def get_parameters
112
+ super
113
+ @address = prompt.ask('Address:', required: true)
114
+ @port = prompt.ask('Port:', convert: lambda(&:to_i), required: true)
115
+ @domain = prompt.ask('Domain:')
116
+ @authentication = prompt.ask('Authentication:')
117
+ @openssl_verify = prompt.ask('Openssl verify mode:')
118
+ @enable_starttls = prompt.yes?('Enable starttls?:', default: true)
119
+ end
120
+
121
+ end
122
+
123
+ class SendMail < Base
124
+
125
+ def get_parameters
126
+ @location = prompt.ask('Location:', default: '/usr/sbin/sendmail', required: true)
127
+ @arguments = prompt.ask('Arguments:', default: '-i -t')
128
+ end
129
+
130
+ def delivery_method
131
+ :sendmail
132
+ end
133
+
134
+ def delivery_settings
135
+ {
136
+ 'location' => @location,
137
+ 'arguments' => @arguments
138
+ }
139
+ end
140
+
141
+ def to_s
142
+ "<SendMail #{@location} #{@arguments}>"
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,204 @@
1
+ module RedmineInstaller
2
+ class Database
3
+ extend Utils
4
+
5
+ def self.create_config(redmine)
6
+ # Maybe: enum_select
7
+ klass = prompt.select('What database do you want use?') do |menu|
8
+ menu.choice 'MySQL', MySQL
9
+ menu.choice 'PostgreSQL', PostgreSQL
10
+ end
11
+
12
+ # Get parameters and create configuration
13
+ database = klass.new(redmine)
14
+ database.get_parameters
15
+ database.make_config
16
+ database
17
+ end
18
+
19
+ def self.init(redmine)
20
+ unless File.exist?(redmine.database_yml_path)
21
+ error "Database configuration files does not exist on #{redmine.root}."
22
+ end
23
+
24
+ definitions = YAML.load_file(redmine.database_yml_path)
25
+ definition = definitions['production']
26
+
27
+ unless definition.is_a?(Hash)
28
+ error 'Unknow database definition'
29
+ end
30
+
31
+ case definition['adapter']
32
+ when 'mysql', 'mysql2'
33
+ klass = MySQL
34
+ when 'pg', 'postgresql'
35
+ klass = PostgreSQL
36
+ else
37
+ error "Unknow database adapter #{definition['adapter']}."
38
+ end
39
+
40
+ database = klass.new(redmine)
41
+ database.set_paramaters(definition)
42
+ database
43
+ end
44
+
45
+ class Base
46
+ include RedmineInstaller::Utils
47
+
48
+ attr_reader :backup
49
+
50
+ def initialize(redmine)
51
+ @redmine = redmine
52
+ end
53
+
54
+ def backuped?
55
+ @backup && File.exist?(@backup)
56
+ end
57
+
58
+ def get_parameters
59
+ @database = prompt.ask('Database:', required: true)
60
+ @host = prompt.ask('Host:', default: 'localhost', required: true)
61
+ @username = prompt.ask('Username:', default: '')
62
+ @password = prompt.mask('Password:', default: '')
63
+ @encoding = prompt.ask('Encoding:', default: 'utf8', required: true)
64
+ @port = prompt.ask('Port:', default: default_port, convert: lambda(&:to_i), required: true)
65
+ end
66
+
67
+ def set_paramaters(definition)
68
+ @database = definition['database']
69
+ @username = definition['username']
70
+ @password = definition['password']
71
+ @encoding = definition['encoding']
72
+ @host = definition['host']
73
+ @port = definition['port']
74
+ end
75
+
76
+ def make_config
77
+ File.open(@redmine.database_yml_path, 'w') do |f|
78
+ f.puts(YAML.dump(build))
79
+ end
80
+ end
81
+
82
+ def make_backup(dir)
83
+ puts 'Database backuping'
84
+ @backup = File.join(dir, "#{@database}.sql")
85
+ Kernel.system backup_command(@backup)
86
+ end
87
+
88
+ # Recreate database should be done in 2 commands because of
89
+ # postgre's '--command' options which can do only 1 operations.
90
+ # Otherwise result is unpredictable.
91
+ def do_restore(file)
92
+ puts 'Database cleaning'
93
+ Kernel.system drop_database_command
94
+ Kernel.system create_database_command
95
+
96
+ puts 'Database restoring'
97
+ Kernel.system restore_command(file)
98
+ end
99
+
100
+ def build
101
+ data = {}
102
+ data['adapter'] = adapter_name
103
+ data['database'] = @database
104
+ data['username'] = @username if @username.present?
105
+ data['password'] = @password if @password.present?
106
+ data['encoding'] = @encoding
107
+ data['host'] = @host
108
+ data['port'] = @port
109
+
110
+ {
111
+ 'production' => data,
112
+ 'development' => data
113
+ }
114
+ end
115
+
116
+ def to_s
117
+ "<#{class_name} #{@username}@#{@host}:#{@port} (#{@encoding})>"
118
+ end
119
+
120
+ end
121
+
122
+ class MySQL < Base
123
+
124
+ def default_port
125
+ 3306
126
+ end
127
+
128
+ def adapter_name
129
+ 'mysql2'
130
+ end
131
+
132
+ def command_args
133
+ args = []
134
+ args << "--host=#{@host}" unless @host.to_s.empty?
135
+ args << "--port=#{@port}" unless @port.to_s.empty?
136
+ args << "--user=#{@username}" unless @username.to_s.empty?
137
+ args << "--password=#{@password}" unless @password.to_s.empty?
138
+ args.join(' ')
139
+ end
140
+
141
+ def create_database_command
142
+ "mysql #{command_args} --execute=\"create database #{@database}\""
143
+ end
144
+
145
+ def drop_database_command
146
+ "mysql #{command_args} --execute=\"drop database #{@database}\""
147
+ end
148
+
149
+ def backup_command(file)
150
+ "mysqldump --add-drop-database --compact --result-file=#{file} #{command_args} #{@database}"
151
+ end
152
+
153
+ def restore_command(file)
154
+ "mysql #{command_args} #{@database} < #{file}"
155
+ end
156
+
157
+ end
158
+
159
+ class PostgreSQL < Base
160
+
161
+ def default_port
162
+ 5432
163
+ end
164
+
165
+ def adapter_name
166
+ 'postgresql'
167
+ end
168
+
169
+ def command_args
170
+ args = []
171
+ args << "--host=#{@host}" unless @host.to_s.empty?
172
+ args << "--port=#{@port}" unless @port.to_s.empty?
173
+ args << "--username=#{@username}" unless @username.to_s.empty?
174
+ args.join(' ')
175
+ end
176
+
177
+ def cli_password
178
+ if @password.present?
179
+ "PGPASSWORD=\"#{@password}\""
180
+ else
181
+ ''
182
+ end
183
+ end
184
+
185
+ def create_database_command
186
+ "#{cli_password} psql #{command_args} --command=\"create database #{@database};\""
187
+ end
188
+
189
+ def drop_database_command
190
+ "#{cli_password} psql #{command_args} --command=\"drop database #{@database};\""
191
+ end
192
+
193
+ def backup_command(file)
194
+ "#{cli_password} pg_dump --clean #{command_args} --format=custom --file=#{file} #{@database}"
195
+ end
196
+
197
+ def restore_command(file)
198
+ "#{cli_password} pg_restore --clean #{command_args} --dbname=#{@database} #{file} 2>/dev/null"
199
+ end
200
+
201
+ end
202
+
203
+ end
204
+ end