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
@@ -0,0 +1,81 @@
1
+ # $stdin.sync = true
2
+ # $stdout.sync = true
3
+
4
+ # # require 'redmine-installer/spec/cursor'
5
+
6
+ # class TestPrompt < TTY::Prompt
7
+
8
+ # def initialize(*args)
9
+ # # @input = StringIO.new
10
+ # # @output = StringIO.new
11
+ # # super(input: @input, output: @output)
12
+ # super
13
+ # @pastel = Pastel.new(enabled: false)
14
+ # end
15
+
16
+ # end
17
+
18
+ # module RedmineInstaller
19
+
20
+ # # def self.prompt
21
+ # # @prompt ||= TestPrompt.new
22
+ # # end
23
+
24
+ # def self.pastel
25
+ # @pastel ||= Pastel.new(enabled: false)
26
+ # end
27
+
28
+ # end
29
+
30
+ # module TTY
31
+ # module Cursor
32
+
33
+ # singleton_methods.each do |name|
34
+ # class_eval <<-METHODS
35
+
36
+ # def #{name}(*)
37
+ # ''
38
+ # end
39
+
40
+ # def self.#{name}(*)
41
+ # ''
42
+ # end
43
+
44
+ # METHODS
45
+ # end
46
+
47
+ # end
48
+ # end
49
+
50
+ $stdin.sync = true
51
+ $stdout.sync = true
52
+
53
+ module TTY::Cursor
54
+
55
+ singleton_methods.each do |name|
56
+ class_eval <<-METHODS
57
+
58
+ def #{name}(*)
59
+ ''
60
+ end
61
+
62
+ def self.#{name}(*)
63
+ ''
64
+ end
65
+
66
+ METHODS
67
+ end
68
+
69
+ end
70
+
71
+ class TestPrompt < TTY::Prompt
72
+
73
+ def initialize(*args)
74
+ super
75
+ @pastel = Pastel.new(enabled: false)
76
+ end
77
+
78
+ end
79
+
80
+ RedmineInstaller.instance_variable_set(:@prompt, TestPrompt.new)
81
+ RedmineInstaller.instance_variable_set(:@pastel, Pastel.new(enabled: false))
@@ -1,94 +1,35 @@
1
- ##
2
- # Parent for all commands (Install, Upgrade, Backup)
3
- #
4
- module Redmine::Installer
1
+ module RedmineInstaller
5
2
  class Task
3
+ include Utils
6
4
 
7
- attr_accessor :redmine_root
8
- attr_accessor :tmp_redmine_root
9
- attr_accessor :options
10
- attr_accessor :settings
11
- attr_accessor :env
5
+ attr_reader :options
12
6
 
13
- attr_reader :steps
7
+ def initialize(**options)
8
+ @options = OpenStruct.new(options)
14
9
 
15
- def initialize(options={})
16
- self.options = options
17
- self.settings = {}
18
- self.env = options[:env]
19
-
20
- # Initialize steps for task
21
- @steps = {}
22
- index = 1
23
- self.class::STEPS.each do |step|
24
- @steps[index] = step.new(index, self)
25
- index += 1
26
- end
10
+ logger.info "#{class_name} initialized with #{options}"
11
+ logger.info "RUBY_VERSION: #{RUBY_VERSION}"
12
+ logger.info "USER: #{env_user}"
27
13
  end
28
14
 
29
15
  def run
30
- @steps.each do |_, step|
31
- step.prepare
32
- end
33
-
34
- @steps.each do |_, step|
35
- step.print_title
36
- step.print_header
37
- step.up
38
- step.print_footer
39
- step.ran = true
40
- puts
41
- end
42
-
43
- @steps.each do |_, step|
44
- step.final
45
- end
16
+ up
17
+ rescue => e
18
+ @error = e
46
19
 
47
- Dir.chdir(redmine_root) do
48
- Redmine::Installer::Plugin::RedminePlugin.all.each do |plugin|
49
- plugin.final(self)
50
- end
51
- end
52
- rescue Redmine::Installer::Error => e
53
- # Rescue from error comes from installer
54
- # run steps again for cleaning
55
- @steps.values.reverse.each do |step|
56
- next unless step.ran
57
- step.down
58
- end
20
+ logger.error(e.message)
21
+ logger.error(*e.backtrace)
59
22
 
60
- $stderr.puts(ANSI.red, e.message, ANSI.clear)
61
- $stderr.flush
62
- exit(1)
63
- end
23
+ puts pastel.red(e.message)
64
24
 
65
- # Package is required for install task and
66
- # upgrade with source file
67
- def check_package
68
- if package.nil?
69
- raise Redmine::Installer::Error, I18n.translate(:error_argument_package_is_missing)
70
- end
25
+ down
71
26
  end
72
27
 
73
- def self.step
74
- Redmine::Installer::Step
28
+ def up
29
+ raise NotImplementedError
75
30
  end
76
31
 
77
- # Creating methods for recognition type of task
78
- #
79
- # == Examples:
80
- # class Install < Task
81
- # end
82
- #
83
- # Install.new.install? #=> true
84
- #
85
- def self.inherited(child)
86
- method_name = "#{child.class_name.downcase}?".to_sym
87
-
88
- define_method(method_name) { false }
89
- child.send(:define_method, method_name) { true }
90
-
91
- super
32
+ def down
92
33
  end
93
34
 
94
35
  end
@@ -0,0 +1,12 @@
1
+ module RedmineInstaller
2
+ class TaskModule
3
+ include Utils
4
+
5
+ attr_reader :task
6
+
7
+ def initialize(task)
8
+ @task = task
9
+ end
10
+
11
+ end
12
+ end
@@ -1,68 +1,60 @@
1
- ##
2
- # Backup redmine
3
- #
4
- # You can upgrade current redmine by archive or currently defined git repository.
5
- # If your redmine contain plugins which are not part of new package - all these
6
- # plugins will be kept otherwise are replaced with those from package.
7
- #
8
- # Final step will ask you if you want save steps configuration.
9
- # If you say YES, configuration will be stored as profile so next time
10
- # you can upgrade redmine faster.
11
- #
12
- # redmine upgrade PACKAGE --profile PROFILE_ID
13
- # Profiles are stored on HOME_FOLDER/.redmine-installer-profiles.yml.
14
- #
15
- # == Steps:
16
- # 1. Redmine root - where should be new redmine located
17
- # 2. Load package - extract package
18
- # 3. Validation - current redmine should be valid
19
- # 4. Backup - backup current redmine (see backup section)
20
- # 5. Upgrading - install commands are executed
21
- # 6. Moving redmine - redmine is moved from temporarily folder to given redmine_root
22
- # 7. Profile saving - generating profile (see profile section)
23
- #
24
- # == Usage:
25
- #
26
- # From archive::
27
- # # minimal
28
- # redmine upgrade PATH_TO_PACKAGE
29
- #
30
- # # full
31
- # redmine upgrade PATH_TO_PACKAGE --env ENV1,ENV2,ENV3
32
- #
33
- # From git::
34
- # # minimal
35
- # redmine upgrade --source git
36
- #
37
- # # full
38
- # redmine upgrade --source git --env ENV1,ENV2,ENV3
39
- #
40
- module Redmine::Installer
41
- class Upgrade < Task
1
+ module RedmineInstaller
2
+ class Upgrade < Install
42
3
 
43
- STEPS = [
44
- step::EnvCheck,
45
- step::RedmineRoot,
46
- step::LoadPackage,
47
- step::Validation,
48
- step::Backup,
49
- step::Upgrade,
50
- step::MoveRedmine
51
- ]
4
+ def up
5
+ if options.profile
6
+ @profile = Profile.get!(options.profile)
7
+ end
52
8
 
53
- attr_accessor :package
9
+ if @profile
10
+ @target_redmine.load_profile(@profile)
11
+ end
54
12
 
55
- def initialize(package, options={})
56
- self.package = package
57
- super(options)
13
+ @environment.check
14
+ @target_redmine.ensure_and_valid_root
15
+ @target_redmine.validate
16
+ @target_redmine.check_running_state
58
17
 
59
- check_package if options[:source] == 'file'
18
+ @package.ensure_and_valid_package
19
+ @package.extract
20
+
21
+ @temp_redmine.root = @package.redmine_root
22
+
23
+ @target_redmine.make_backup
24
+
25
+ @temp_redmine.copy_importants_from(@target_redmine)
26
+ @temp_redmine.copy_missing_plugins_from(@target_redmine)
27
+
28
+ @temp_redmine.upgrade
29
+
30
+ print_title('Finishing installation')
31
+ ok('Cleaning root'){ @target_redmine.delete_root }
32
+ ok('Moving redmine to target directory'){ @target_redmine.move_from(@temp_redmine) }
33
+ ok('Cleanning up'){ @package.clean_up }
34
+ ok('Moving installer log'){ logger.move_to(@target_redmine, suffix: 'upgrade') }
35
+
36
+ puts
37
+ puts pastel.bold('Redmine was upgraded')
38
+ logger.info('Redmine was upgraded')
39
+
40
+ if @profile.nil? && prompt.yes?('Do you want save steps for further use?', default: false)
41
+ profile = Profile.new
42
+ @target_redmine.save_profile(profile)
43
+ profile.save
44
+ end
60
45
  end
61
46
 
62
- def run
63
- Redmine::Installer::Profile.load(self, options[:profile])
64
- super
65
- Redmine::Installer::Profile.save(self) if options[:profile].nil?
47
+ def down
48
+ @temp_redmine.clean_up
49
+ @package.clean_up
50
+
51
+ if @target_redmine.database && @target_redmine.database.backuped?
52
+ puts
53
+ puts "Database have been backed up on #{pastel.bold(@target_redmine.database.backup)}"
54
+ end
55
+
56
+ puts
57
+ puts "(Log is located on #{pastel.bold(logger.path)})"
66
58
  end
67
59
 
68
60
  end
@@ -1,248 +1,61 @@
1
- require 'fileutils'
2
- require 'notifier'
3
- require 'ansi'
4
- require 'io/console'
5
-
6
- module Redmine::Installer
1
+ module RedmineInstaller
7
2
  module Utils
8
3
 
9
- def self.included(base)
10
- base.send :extend, Methods
11
- base.send :include, Methods
4
+ PROGRESSBAR_FORMAT = ':elapsed [:bar] :percent'
12
5
 
13
- base.class_eval do
14
- self.send(:const_set, 'Git', Redmine::Installer::Git)
15
- end
6
+ def class_name
7
+ self.class.name.split('::').last
16
8
  end
17
9
 
18
- module Methods
19
-
20
- # =======================================================================
21
- # Generals
22
-
23
- def plugin
24
- Redmine::Installer::Plugin
25
- end
26
-
27
- def command
28
- Redmine::Installer::Command.instance
29
- end
30
-
31
- def error(*args)
32
- # Translate message
33
- if args.first.is_a?(Symbol)
34
- message = translate(*args)
35
- else
36
- message = args.first
37
- end
38
-
39
- # Colorize message
40
- colorize(message)
41
-
42
- raise Redmine::Installer::Error, message
43
- end
44
-
45
- # Try create a dir
46
- # When mkdir raise an error (permission problem) method
47
- # ask user if wants exist or try again
48
- def try_create_dir(dir)
49
- begin
50
- FileUtils.mkdir_p(dir)
51
- rescue
52
- choices = {}
53
- choices[:exit] = t(:exit)
54
- choices[:try_again] = t(:try_again)
55
-
56
- answer = choose(t(:dir_not_exist_and_cannot_be_created, dir: dir), choices, default: :exit)
57
-
58
- case answer
59
- when :exit
60
- error ''
61
- when :try_again
62
- try_create_dir(dir)
63
- end
64
- end
65
- end
66
-
67
- # Check if there are plugins in plugin dir
68
- def some_plugins?
69
- Dir.glob(File.join('plugins', '*')).select{|record| File.directory?(record)}.any?
70
- end
71
-
72
- def windows?
73
- RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
74
- end
75
-
76
- def root?
77
- Process.euid == 0
78
- end
79
-
80
-
81
- # =======================================================================
82
- # Input, output
83
-
84
- # Print message to stdout
85
- def say(message, lines=0)
86
- # Translate message
87
- if message.is_a?(Symbol)
88
- message = translate(message)
89
- end
90
-
91
- # Colorize message
92
- colorize(message)
93
-
94
- $stdout.print(message)
95
- lines.times { $stdout.puts }
96
- $stdout.flush
97
- end
98
-
99
- # Colorize text based on XML marks
100
- #
101
- # == Examples:
102
- # colorize("<bright><on_black><white>text</white></on_black></bright>")
103
- # # => "\e[1m\e[40m\e[37mtext\e[0m\e[0m\e[0m"
104
- #
105
- def colorize(text)
106
- return unless text.is_a?(String)
107
-
108
- text.gsub!(/<([a-zA-Z0-9_]+)>/) do
109
- if ANSI::CHART.has_key?($1.to_sym)
110
- ANSI.send($1)
111
- else
112
- "<#{$1}>"
113
- end
114
- end
115
- text.gsub!(/<\/([a-zA-Z0-9_]+)>/) do
116
- if ANSI::CHART.has_key?($1.to_sym)
117
- ANSI.clear
118
- else
119
- "</#{$1}>"
120
- end
121
- end
122
- end
123
-
124
- # Instead of `super` take only what I need
125
- def gets(hide=false)
126
- if hide
127
- input = $stdin.noecho{|io| io.gets}.to_s.chomp
128
- $stdout.puts # noecho is also for enter
129
- input
130
- else
131
- $stdin.gets.to_s.chomp
132
- end
133
- end
134
-
135
- # Asking on 1 line
136
- def ask(message=nil, options={})
137
- # Translate message
138
- if message.is_a?(Symbol)
139
- message = translate(message)
140
- end
141
- default = options[:default]
142
-
143
- if default
144
- message << " [#{default}]"
145
- end
146
-
147
- if !options[:without_colon]
148
- message << ': '
149
- end
150
-
151
- say(message)
152
- input = gets(options[:hide])
153
-
154
- # Ctrl-D or enter was pressed
155
- return default if input.empty?
156
-
157
- input
158
- end
159
-
160
- # User can choose from selection
161
- def choose(message, choices, options={})
162
- choices = choices.to_a
163
- default = options[:default]
164
- index = 1
165
-
166
- say(message, 1) unless message.nil?
167
- choices.each do |(key, message)|
168
- if key == default
169
- pre = '*'
170
- else
171
- pre = ' '
172
- end
173
-
174
- say(" #{pre}#{index}) #{message}", 1)
175
- index += 1
176
- end
177
-
178
- input = ask('> ', without_colon: true).to_i
179
- puts
180
-
181
- # Without default is input 0
182
- return default if input.zero? || input > choices.size
183
-
184
- choices[input-1][0]
185
- end
186
-
187
- # Say 'Do you want?'
188
- # -> YES, NO
189
- #
190
- def confirm(message, default=true)
191
- # Translate message
192
- if message.is_a?(Symbol)
193
- message = translate(message)
194
- end
195
-
196
- # Colorize message
197
- colorize(message)
198
-
199
- yes = t(:yes_t)
200
- no = t(:no_t)
201
-
202
- if default
203
- yes.upcase!
204
- else
205
- no.upcase!
206
- end
207
-
208
- message << " (#{yes}/#{no}): "
10
+ def logger
11
+ RedmineInstaller.logger
12
+ end
209
13
 
210
- $stdout.print(message)
211
- answer = gets
14
+ def prompt
15
+ RedmineInstaller.prompt
16
+ end
212
17
 
213
- return default if answer.empty?
18
+ def pastel
19
+ RedmineInstaller.pastel
20
+ end
214
21
 
215
- if answer[0].downcase == yes[0].downcase
216
- return true
217
- else
218
- return false
219
- end
220
- end
22
+ def run_command(cmd, title=nil)
23
+ RedmineInstaller::Command.new(cmd, title: title).run
24
+ end
221
25
 
26
+ def ok(title)
27
+ print "#{title} ... "
28
+ yield
29
+ puts pastel.green('OK')
30
+ rescue => e
31
+ puts pastel.red('FAIL')
32
+ raise
33
+ end
222
34
 
223
- # =======================================================================
224
- # Localizations
35
+ def env_user
36
+ ENV['USER'] || ENV['USERNAME']
37
+ end
225
38
 
226
- def translate(*args)
227
- I18n.translate(*args)
39
+ # Try create a dir
40
+ # When mkdir raise an error (permission problem) method ask user if wants exist or try again
41
+ def create_dir(dir)
42
+ FileUtils.mkdir_p(dir)
43
+ rescue
44
+ if prompt.yes?("Dir #{dir} doesn't exist and can't be created. Try again?", default: true)
45
+ create_dir(dir)
46
+ else
47
+ error('Dir creating was aborted by user.')
228
48
  end
229
- alias_method :t, :translate
230
-
231
-
232
- # =======================================================================
233
- # Notifications
49
+ end
234
50
 
235
- def notif(title, message=nil, image=nil)
236
- return unless Redmine::Installer.config.notif
51
+ def print_title(title)
52
+ puts
53
+ puts pastel.white.on_black(title)
54
+ end
237
55
 
238
- thread = ::Notifier.notify(
239
- title: title.to_s,
240
- message: message.to_s,
241
- image: image.to_s
242
- )
243
- thread.join
244
- end
56
+ def error(message)
57
+ raise RedmineInstaller::Error, message
58
+ end
245
59
 
246
- end # Methods
247
- end # Utils
248
- end # Redmine::Installer
60
+ end
61
+ end