redmine-installer 1.0.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 (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +25 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +273 -0
  6. data/Rakefile +7 -0
  7. data/bin/redmine +8 -0
  8. data/lib/redmine-installer.rb +72 -0
  9. data/lib/redmine-installer/backup.rb +48 -0
  10. data/lib/redmine-installer/cli.rb +90 -0
  11. data/lib/redmine-installer/command.rb +142 -0
  12. data/lib/redmine-installer/config_param.rb +90 -0
  13. data/lib/redmine-installer/error.rb +5 -0
  14. data/lib/redmine-installer/exec.rb +158 -0
  15. data/lib/redmine-installer/ext/module.rb +7 -0
  16. data/lib/redmine-installer/ext/string.rb +15 -0
  17. data/lib/redmine-installer/git.rb +51 -0
  18. data/lib/redmine-installer/helper.rb +5 -0
  19. data/lib/redmine-installer/helpers/generate_config.rb +29 -0
  20. data/lib/redmine-installer/install.rb +56 -0
  21. data/lib/redmine-installer/locales/cs.yml +145 -0
  22. data/lib/redmine-installer/locales/en.yml +146 -0
  23. data/lib/redmine-installer/plugin.rb +9 -0
  24. data/lib/redmine-installer/plugins/base.rb +28 -0
  25. data/lib/redmine-installer/plugins/database.rb +168 -0
  26. data/lib/redmine-installer/plugins/email_sending.rb +82 -0
  27. data/lib/redmine-installer/plugins/redmine_plugin.rb +30 -0
  28. data/lib/redmine-installer/plugins/web_server.rb +26 -0
  29. data/lib/redmine-installer/profile.rb +74 -0
  30. data/lib/redmine-installer/step.rb +15 -0
  31. data/lib/redmine-installer/steps/backup.rb +120 -0
  32. data/lib/redmine-installer/steps/base.rb +60 -0
  33. data/lib/redmine-installer/steps/database_config.rb +15 -0
  34. data/lib/redmine-installer/steps/email_config.rb +11 -0
  35. data/lib/redmine-installer/steps/install.rb +21 -0
  36. data/lib/redmine-installer/steps/load_package.rb +180 -0
  37. data/lib/redmine-installer/steps/move_redmine.rb +22 -0
  38. data/lib/redmine-installer/steps/redmine_root.rb +29 -0
  39. data/lib/redmine-installer/steps/upgrade.rb +55 -0
  40. data/lib/redmine-installer/steps/validation.rb +38 -0
  41. data/lib/redmine-installer/steps/webserver_config.rb +22 -0
  42. data/lib/redmine-installer/task.rb +85 -0
  43. data/lib/redmine-installer/upgrade.rb +68 -0
  44. data/lib/redmine-installer/utils.rb +233 -0
  45. data/lib/redmine-installer/version.rb +5 -0
  46. data/redmine-installer.gemspec +25 -0
  47. data/spec/lib/install_spec.rb +46 -0
  48. data/spec/lib/upgrade_spec.rb +62 -0
  49. data/spec/load_redmine.rb +24 -0
  50. data/spec/spec_helper.rb +30 -0
  51. metadata +130 -0
@@ -0,0 +1,85 @@
1
+ ##
2
+ # Parent for all commands (Install, Upgrade, Backup)
3
+ #
4
+ module Redmine::Installer
5
+ class Task
6
+
7
+ attr_accessor :redmine_root
8
+ attr_accessor :tmp_redmine_root
9
+ attr_accessor :options
10
+ attr_accessor :settings
11
+ attr_accessor :env
12
+
13
+ attr_reader :steps
14
+
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
27
+ end
28
+
29
+ def run
30
+ @steps.each do |id, step|
31
+ step.print_title
32
+ step.print_header
33
+ step.up
34
+ step.print_footer
35
+ step.ran = true
36
+ puts # new line
37
+ end
38
+
39
+ @steps.each do |id, step|
40
+ step.final_step
41
+ end
42
+ rescue Redmine::Installer::Error => e
43
+ # Rescue from error comes from installer
44
+ # run steps again for cleaning
45
+ @steps.values.reverse.each do |step|
46
+ next unless step.ran
47
+ step.down
48
+ end
49
+
50
+ $stderr.puts(ANSI.red, e.message, ANSI.clear)
51
+ $stderr.flush
52
+ exit(1)
53
+ end
54
+
55
+ # Package is required for install task and
56
+ # upgrade with source file
57
+ def check_package
58
+ if package.nil?
59
+ raise Redmine::Installer::Error, I18n.translate(:error_argument_package_is_missing)
60
+ end
61
+ end
62
+
63
+ def self.step
64
+ Redmine::Installer::Step
65
+ end
66
+
67
+ # Creating methods for recognition type of task
68
+ #
69
+ # == Examples:
70
+ # class Install < Task
71
+ # end
72
+ #
73
+ # Install.new.install? #=> true
74
+ #
75
+ def self.inherited(child)
76
+ method_name = "#{child.class_name.downcase}?".to_sym
77
+
78
+ define_method(method_name) { false }
79
+ child.send(:define_method, method_name) { true }
80
+
81
+ super
82
+ end
83
+
84
+ end
85
+ end
@@ -0,0 +1,68 @@
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
42
+
43
+ STEPS = [
44
+ step::RedmineRoot,
45
+ step::LoadPackage,
46
+ step::Validation,
47
+ step::Backup,
48
+ step::Upgrade,
49
+ step::MoveRedmine
50
+ ]
51
+
52
+ attr_accessor :package
53
+
54
+ def initialize(package, options={})
55
+ self.package = package
56
+ super(options)
57
+
58
+ check_package if options[:source] == 'file'
59
+ end
60
+
61
+ def run
62
+ Redmine::Installer::Profile.load(self, options[:profile])
63
+ super
64
+ Redmine::Installer::Profile.save(self) if options[:profile].nil?
65
+ end
66
+
67
+ end
68
+ end
@@ -0,0 +1,233 @@
1
+ require 'fileutils'
2
+ require 'notifier'
3
+ require 'ansi'
4
+
5
+ module Redmine::Installer
6
+ module Utils
7
+
8
+ def self.included(base)
9
+ base.send :extend, Methods
10
+ base.send :include, Methods
11
+
12
+ base.class_eval do
13
+ self.send(:const_set, 'Git', Redmine::Installer::Git)
14
+ end
15
+ end
16
+
17
+ module Methods
18
+
19
+ # =======================================================================
20
+ # Generals
21
+
22
+ def plugin
23
+ Redmine::Installer::Plugin
24
+ end
25
+
26
+ def command
27
+ Redmine::Installer::Command.instance
28
+ end
29
+
30
+ def error(*args)
31
+ # Translate message
32
+ if args.first.is_a?(Symbol)
33
+ message = translate(*args)
34
+ else
35
+ message = args.first
36
+ end
37
+
38
+ # Colorize message
39
+ colorize(message)
40
+
41
+ raise Redmine::Installer::Error, message
42
+ end
43
+
44
+ # Try create a dir
45
+ # When mkdir raise an error (permission problem) method
46
+ # ask user if wants exist or try again
47
+ def try_create_dir(dir)
48
+ begin
49
+ FileUtils.mkdir_p(dir)
50
+ rescue
51
+ choices = {}
52
+ choices[:exit] = t(:exit)
53
+ choices[:try_again] = t(:try_again)
54
+
55
+ answer = choose(t(:dir_not_exist_and_cannot_be_created, dir: dir), choices, default: :exit)
56
+
57
+ case answer
58
+ when :exit
59
+ error ''
60
+ when :try_again
61
+ try_create_dir(dir)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Check if there are plugins in plugin dir
67
+ def some_plugins?
68
+ Dir.glob(File.join('plugins', '*')).select{|record| File.directory?(record)}.any?
69
+ end
70
+
71
+
72
+ # =======================================================================
73
+ # Input, output
74
+
75
+ # Print message to stdout
76
+ def say(message, lines=0)
77
+ # Translate message
78
+ if message.is_a?(Symbol)
79
+ message = translate(message)
80
+ end
81
+
82
+ # Colorize message
83
+ colorize(message)
84
+
85
+ $stdout.print(message)
86
+ lines.times { $stdout.puts }
87
+ $stdout.flush
88
+ end
89
+
90
+ # Colorize text based on XML marks
91
+ #
92
+ # == Examples:
93
+ # colorize("<bright><on_black><white>text</white></on_black></bright>")
94
+ # # => "\e[1m\e[40m\e[37mtext\e[0m\e[0m\e[0m"
95
+ #
96
+ def colorize(text)
97
+ return unless text.is_a?(String)
98
+
99
+ text.gsub!(/<([a-zA-Z0-9_]+)>/) do
100
+ if ANSI::CHART.has_key?($1.to_sym)
101
+ ANSI.send($1)
102
+ else
103
+ "<#{$1}>"
104
+ end
105
+ end
106
+ text.gsub!(/<\/([a-zA-Z0-9_]+)>/) do
107
+ if ANSI::CHART.has_key?($1.to_sym)
108
+ ANSI.clear
109
+ else
110
+ "</#{$1}>"
111
+ end
112
+ end
113
+ end
114
+
115
+ # Instead of `super` take only what I need
116
+ def gets
117
+ $stdin.gets.to_s.chomp
118
+ end
119
+
120
+ # Asking on 1 line
121
+ def ask(message=nil, options={})
122
+ # Translate message
123
+ if message.is_a?(Symbol)
124
+ message = translate(message)
125
+ end
126
+ default = options[:default]
127
+
128
+ if default
129
+ message << " [#{default}]"
130
+ end
131
+
132
+ if !options[:without_colon]
133
+ message << ': '
134
+ end
135
+
136
+ say(message)
137
+ input = gets
138
+
139
+ # Ctrl-D or enter was pressed
140
+ return default if input.empty?
141
+
142
+ input
143
+ end
144
+
145
+ # User can choose from selection
146
+ def choose(message, choices, options={})
147
+ choices = choices.to_a
148
+ default = options[:default]
149
+ index = 1
150
+
151
+ say(message, 1) unless message.nil?
152
+ choices.each do |(key, message)|
153
+ if key == default
154
+ pre = '*'
155
+ else
156
+ pre = ' '
157
+ end
158
+
159
+ say(" #{pre}#{index}) #{message}", 1)
160
+ index += 1
161
+ end
162
+
163
+ input = ask('> ', without_colon: true).to_i
164
+ puts
165
+
166
+ # Without default is input 0
167
+ return default if input.zero? || input > choices.size
168
+
169
+ choices[input-1][0]
170
+ end
171
+
172
+ # Say 'Do you want?'
173
+ # -> YES, NO
174
+ #
175
+ def confirm(message, default=true)
176
+ # Translate message
177
+ if message.is_a?(Symbol)
178
+ message = translate(message)
179
+ end
180
+
181
+ # Colorize message
182
+ colorize(message)
183
+
184
+ yes = t(:yes_t)
185
+ no = t(:no_t)
186
+
187
+ if default
188
+ yes.upcase!
189
+ else
190
+ no.upcase!
191
+ end
192
+
193
+ message << " (#{yes}/#{no}): "
194
+
195
+ $stdout.print(message)
196
+ answer = gets
197
+
198
+ return default if answer.empty?
199
+
200
+ if answer[0].downcase == yes[0].downcase
201
+ return true
202
+ else
203
+ return false
204
+ end
205
+ end
206
+
207
+
208
+ # =======================================================================
209
+ # Localizations
210
+
211
+ def translate(*args)
212
+ I18n.translate(*args)
213
+ end
214
+ alias_method :t, :translate
215
+
216
+
217
+ # =======================================================================
218
+ # Notifications
219
+
220
+ def notif(title, message=nil, image=nil)
221
+ return unless Redmine::Installer.config.notif
222
+
223
+ thread = ::Notifier.notify(
224
+ title: title.to_s,
225
+ message: message.to_s,
226
+ image: image.to_s
227
+ )
228
+ thread.join
229
+ end
230
+
231
+ end # Methods
232
+ end # Utils
233
+ end # Redmine::Installer
@@ -0,0 +1,5 @@
1
+ module Redmine
2
+ module Installer
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'redmine-installer/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "redmine-installer"
8
+ spec.version = Redmine::Installer::VERSION
9
+ spec.authors = ["Ondřej Moravčík"]
10
+ spec.email = ["moravcik.ondrej@gmail.com"]
11
+ spec.summary = %q{Easy way how install/upgrade redmine or plugin.}
12
+ spec.description = %q{Redmine-installer can fully install/upgrade redmine and will
13
+ generate template for different server. All actions can be saved
14
+ for further use.}
15
+ spec.homepage = "https://github.com/ondra-m/redmine-installer"
16
+ spec.license = "MIT"
17
+
18
+ spec.files = `git ls-files -z`.split("\x0")
19
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
20
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake"
25
+ end
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Redmine::Installer::Install do
4
+
5
+ before(:example) do
6
+ @dir = Dir.mktmpdir
7
+ end
8
+
9
+ after(:example) do
10
+ FileUtils.remove_entry_secure(@dir)
11
+ end
12
+
13
+ let(:package1) { LoadRedmine.get('2.4.7') }
14
+
15
+ context 'mysql' do
16
+ let(:host) { RSpec.configuration.mysql[:host] }
17
+ let(:port) { RSpec.configuration.mysql[:port] }
18
+ let(:username) { RSpec.configuration.mysql[:username] }
19
+ let(:password) { RSpec.configuration.mysql[:password] }
20
+
21
+ before(:example) do
22
+ system("mysql -h #{host} --port #{port} -u #{username} -p#{password} -e 'drop database test1'")
23
+ end
24
+
25
+ it 'install' do
26
+ # redmine root -> temp dir
27
+ # type of db -> mysql
28
+ # database -> test1
29
+ # host -> configuration
30
+ # username -> configuration
31
+ # password -> configuration
32
+ # encoding -> utf8
33
+ # port -> configuration
34
+ # email configuration -> skip
35
+ # webserver -> skip
36
+
37
+ allow($stdin).to receive(:gets).and_return(
38
+ @dir, '1', 'test1', host, username, password, 'utf8', port, '999', '999'
39
+ )
40
+
41
+ r_installer = Redmine::Installer::Install.new(package1, {})
42
+ expect { r_installer.run }.to_not raise_error
43
+ end
44
+ end
45
+
46
+ end