redmine-installer 1.0.7 → 2.0.0.rc1

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 (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